自己尝试实现一个事件中心 EventLoop
。
生成器(generator
)
如下使用关键字 yield
来产生一个生成器,在生成器中函数可以暂时离开原来的状态执行外部的逻辑。
def generator_function():
count = 0
while True:
print('start yield')
yield count
print('end yield')
count ++
for i in generator_function():
print(i)
生成器是实现 Eventloop
最重要的部分,我们可以构建很多生成器,通过一个循环来协同执行生成器里面的逻辑,这样我们就可以实现简单的事件循环。
简单的 Eventloop
如下代码,我们用 while True
实现一个简单的 Eventloop
。
def func1():
yield
print('logic1')
yield
print('logic2')
# ...
def func2():
yield
print('logic3')
yield
print('logic4')
# ...
coro1 = func1()
coro2 = func2()
coros = [coro1, coro2]
while True:
if len(coros) == 0:
break
coro = coros.pop()
try:
next(coro)
coros.insert(0, coro)
except StopIteration:
pass
我们可以用 yield from
来将生成器提交到上层。
含 yield from
的 Eventloop
def func1():
yield
print('logic1')
yield
print('logic2')
# ...
def func2():
yield
print('logic3')
yield
print('logic4')
# ...
def func3():
print('logic5')
yield from func1()
print('logic6')
yield from func2()
# ...
coro1 = func1()
coro2 = func2()
coro3 = func3()
coros = [coro1, coro2, coro3]
while True:
if len(coros) == 0:
break
coro = coros.pop()
try:
next(coro)
coros.insert(0, coro)
except StopIteration:
pass
有了 yield from
我们可以实现复杂点的 Eventloop
使用 async
和 await
def func1():
yield
print('logic1')
yield
print('logic2')
# ...
def func2():
yield
print('logic3')
yield
print('logic4')
# ...
async def func3():
print('logic5')
await func1()
print('logic6')
await func2()
# ...
coro1 = func1()
coro2 = func2()
coro3 = func3()
coros = [coro1, coro2, coro3]
while True:
if len(coros) == 0:
break
coro = coros.pop()
try:
next(coro)
coros.insert(0, coro)
except StopIteration:
pass
在 micropython
上 async/await
和 yield from
的作用相同
真正的 Eventloop
根据上面的分析,我们实现自己的 Eventloop
如下:
import time
def ticks_ms():
try:
return time.ticks_ms()
except:
return int(time.time() * 1000)
class Eventloop(object):
def __init__(self):
self.runq = []
self.waitq = []
self.cur_task = None
def call_soon(self, cb):
self.runq.insert(0, cb)
def call_later(self, cb, delay):
self.call_at(cb, delay + ticks_ms())
def call_at(self, cb, t):
self.waitq.insert(0, {'cb': cb, 'call_at': t})
def wait(self, delay=1):
time.sleep(delay / 1000)
def run_forever(self):
while True:
self.cur_task = None
if len(self.runq) == 0:
if len(self.waitq) == 0:
self.wait()
else:
min = self.waitq[0]
for wait in self.waitq:
if min['call_at'] > wait['call_at']:
min = wait
if min['call_at'] <= ticks_ms():
self.waitq.remove(min)
self.call_soon(min['cb'])
continue
else:
self.wait(min['call_at'] - ticks_ms())
else:
delay = 0
cb = self.runq.pop()
self.cur_task = cb
v = False
try:
v = next(cb)
except StopIteration:
continue
if v is False:
continue
elif isinstance(v, int):
delay = v
if delay > 0:
self.call_later(cb, delay)
else:
self.call_soon(cb)
def sleep(t):
yield t * 1000
我们写一个简短的代码测试一下:
# for micropython
from eventloop import Eventloop, sleep
async def func0():
while True:
print('func0')
await sleep(1)
def func1():
while True:
print('func1')
yield from sleep(5)
def func2():
while True:
print('func2')
for y in sleep(3):
yield y
loop = Eventloop()
loop.call_soon(func0())
loop.call_soon(func1())
loop.call_soon(func2())
loop.run_forever()
# for python3
from eventloop import Eventloop, sleep
def func0():
while True:
print('func0')
for y in sleep(1):
yield y
def func1():
while True:
print('func1')
yield from sleep(5)
def func2():
while True:
print('func2')
yield from sleep(3)
loop = Eventloop()
loop.call_soon(func0())
loop.call_soon(func1())
loop.call_soon(func2())
loop.run_forever()
# for python2
from eventloop import Eventloop, sleep
def func0():
while True:
print('func0')
for y in sleep(1):
yield y
def func1():
while True:
print('func1')
for y in sleep(5):
yield y
def func2():
while True:
print('func2')
for y in sleep(3):
yield y
loop = Eventloop()
loop.call_soon(func0())
loop.call_soon(func1())
loop.call_soon(func2())
loop.run_forever()
结语
到这个我们已经实现了一个功能不健全的 Eventloop
,我们通过不同的方式支持不同的 python
实现。
有兴趣的读者可以尝试的实现,Lock
, Future
等好玩的东西,对于了解原理有莫大的帮助。
网友评论