先定义一个协程函数
import asyncio
async def do_some_work(x):
print("Hello:",x)
return "work is done for {}".format(x)
拿到事件循环对象loop容器,将协程对象扔进事件循环对象中触发。
coroutine = do_some_work('test')
loop = asyncio.get_event_loop()
loop.run_until_complete(coroutine)
run_until_complete 是一个阻塞(blocking)调用,直到协程运行结束,它才返回。
Hello: test
实际项目中,往往有多个协程,同时在一个 loop 里运行。为了把多个协程交给 loop实现并发,需要借助 asyncio.gather 或者 asyncio.wait函数。
coroutines = []
for i in range(5):
coroutines.append(do_some_work(i))
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(coroutines))
# loop.run_until_complete(asyncio.gather(*coroutines))
Hello: 4
Hello: 0
Hello: 1
Hello: 2
Hello: 3
如何停止loop?
需要调用loop.stop(), 利用回调函数实现。
import asyncio
import functools
async def do_some_work(x):
print("Hello:",x)
return "work is done for {}".format(x)
def done_callback(loop, future):
loop.stop()
print("callback: ", future.result())
loop = asyncio.new_event_loop() # 创建一个新的loop对象
asyncio.set_event_loop(loop)
futus = asyncio.gather(do_some_work(1), do_some_work(2), do_some_work(3))
futus.add_done_callback(functools.partial(done_callback, loop))
loop.run_forever() # 在调用 stop() 之前将一直运行,restart loop
Hello: 1
Hello: 3
Hello: 2
callback: ['work is done for 1', 'work is done for 2', 'work is done for 3']
彻底关闭loop
以上示例都没有调用 loop.close,好像也没有什么问题。所以到底要不要调 loop.close 呢?
简单来说,loop 只要不关闭,就还可以再运行。
继续运行以下代码。
loop.run_until_complete(do_some_work(4))
Hello: 4
Out[38]: 'work is done for 4'
但是如果关闭了,就不能再运行其他协程了。
loop.close()
loop.run_until_complete(do_some_work(5))
Traceback (most recent call last):
File "D:\anaconda3\envs\tensor-flow\lib\site-packages\IPython\core\interactiveshell.py", line 3291, in run_code
exec(code_obj, self.user_global_ns, self.user_ns)
File "<ipython-input-41-50fd63fec95a>", line 1, in <module>
loop.run_until_complete(do_some_work(5))
File "D:\anaconda3\envs\tensor-flow\lib\asyncio\base_events.py", line 460, in run_until_complete
self._check_closed()
File "D:\anaconda3\envs\tensor-flow\lib\asyncio\base_events.py", line 377, in _check_closed
raise RuntimeError('Event loop is closed')
RuntimeError: Event loop is closed
建议调用 loop.close,以彻底清理 loop 对象防止误用。