最近,micropython V1.8.2实现了Thread,这迎合了大多数应用开发者的需求。其实其他嵌入式如PyMite,Zerynth在很早实现了Thread类。但是,CPython因为GIL的原因,没有严格意义的多线程。而CPython的进程和线程都是基于操作系统构建的,所以一开始micropython没有实现Thread类。也可以理解。
但是micropython实现了yield,生成器,其特点是支持闭包,保持局部变量。所以可以尝试一下协程(co-routine)的写法。以生产P、消费C两个co-routine为例。每执行到yield语句,代表当前routine交出控制权,由另一routine执行。另一routine执行后,当前routine取回控制权,并恢复现场原有的局部变量,继续执行。循环往复。由于是routine自行约定交出条件,属于协作式多任务。被称之为协程。
- import urandom
- def genData():
- data = [i for i in range(4)]
- for i in range(4):
- data[i] = urandom.randint(1,100)
- return data
- def consume():
- moving_sum = 0
- data_seen = 0
- while True:
- print("wait for to consume")
- data = yield # handover to producer routine
- data_seen += len(data)
- moving_sum += sum(data)
- print('Consumed, average %f'%(moving_sum/data_seen))
- def produce(consumer):
- while True:
- data = genData()
- print('Produced %s'%repr(data))
- consumer.send(data)
- yield # handover to consumer routine
- consumer = consume()
- consumer.send(None)
- producer = produce(consumer)
- for i in range(10):
- print ('Producing...')
- next(producer)
复制代码
代码来自网络,在micropython和桌面CPython上均作了测试,两者表现一样棒!【注】micropython通过urandom支持随机数。
协程对于嵌入式C语言开发者比较新,但是C#/Java都支持yield关键字。返回在硬件上是退栈。yield不同于返回。如果硬要在C语言中实现协程,比较麻烦,需要在汇编或者使用“古怪”的C语言语法,不利于维护。有个替代品,mbed OS中有Thread.sleep()。它的sleep()不是local loop。而是将控制权交回RTOS调度器。
看完这篇,希望网友不仅可以利用micropython的新的Thread,还可以利用Python语言本身特性实现多任务。不要像C语言中那样大量使用delay(),sleep()函数。我自己的原则是,如果延时在10ms左右,还可以忍受堵塞其他任务。如果延时超过100ms,使用协程比较合适。
同样道理,利用RTOS开发C语言程序是时候了。标准C语言开发嵌入式裸机:mainloop + timer + callback + ISR,可以构建完整程序,但是delay和sleep目前暂时需要借用RTOS调度器。或许那位网友可以将某些RTOS这部分调度算法单独规划独立成为一个yield宏。