关于python:Asyncio的事件循环

9次阅读

共计 3840 个字符,预计需要花费 10 分钟才能阅读完成。

Asyncio 的事件循环

事件循环

在事件循环中,咱们能够:
- 注销,执行和勾销调用
- 启动子过程,和内部过程进行通信
- 把耗时的函数调用委托给线程池解决

实质上。所有的事件循环都是期待事件产生,而后执行相应的调用。在此之前,咱们须要把行将产生的事件和对应执行的调用互相关联。

事件循环和线程的关系

从 asyncio event loop policy 文档,咱们得悉, event loop policy 是一个 过程 全局对象,管制对该过程内所有 event loop 的治理。
过程的全局 policy 定义了该 policy 管控的 context 的含意,在每个 context 中治理离开独立的 event loop. 默认的 policy 定义的 context 就是以后的 线程 , 也就是说不同的线程是不同的 context,因而有不同的 event loop。
通过定制 event loop policy 扭转 get_event_loop(), set_event_loop(),new_event_loop()的默认行为。
每个 context 中只有一个 running event loop

asyncio 中 asyncio.run(),asyncio.get_event_loop(), asyncio.new_event_loop,asyncio.set_event_loop()的场景

asyncio.get_event_loop()

若:

  • 以后线程为主线程,
  • 以后线程没有启动 event loop,
    以后线程没有调用 async.set_event_loop(None)

调用 asyncio.get_event_loop()办法会生成一个新的默认 event loop, 并设置为以后线程的事件循环。
此时,get_event_loop()相当于:

loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)

若以后 context 有默认的 event loop, 并且没有被 set_event_loop(None),则返回默认 event loop,

aysncio.run()

调用该办法,会生成新的 event loop 并在办法调用完结时敞开该 event loop。应该作为编写的普通用户异步程序的主入口存在。该办法原则上最好只调用一次。此时 asyncio.run()相当于:

new_loop = asyncio.new_event_loop()
asyncio.set_event_loop(new_loop)
new_loop.run_until_complete(coro)
asyncio.set_event_loop(None)
new_loop.close()

示例总结:

>>> import asyncio
>>> async def main(loop,desc: str):
...     cur_loop = asyncio.get_running_loop()
...     if cur_loop is loop:
...         print(desc, ': match')
...     else:
...         print(desc, ': not match')
...     print(f'Current running loop is :{id(cur_loop)}' )
>>> loop = asyncio.get_event_loop()
>>> loop2 = asyncio.get_event_loop()
>>>loop is loop2
True 
# get_event_loop()获得以后 context 默认的 event loop,若没有则新生成一个。>>>
>>> loop.run_until_complete(main(loop, 'loop.run_until_complete'))
loop.run_until_complete : match
Current running loop is :140127062748856
>>> loop.close() 
 #close 以后的默认循环
>>>
>>> loop.run_until_complete(main(loop, 'loop.run_until_complete'))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/shone/miniconda2/envs/python37/lib/python3.7/asyncio/base_events.py", line 560, in run_until_complete
    self._check_closed()
  File "/home/shone/miniconda2/envs/python37/lib/python3.7/asyncio/base_events.py", line 480, in _check_closed
    raise RuntimeError('Event loop is closed')
RuntimeError: Event loop is closed

# close()之后,这个 event loop 就彻底费了,然而, 只有不调用 set_event_loop(otherloop), 则 loop 仍然是以后 context 的默认 event loop。>>>
>>> loop3 = asyncio.new_event_loop()
>>> loop3.run_until_complete(main(loop, 'loop.run_until_complete'))
loop.run_until_complete : not match
Current running loop is :140127033794456
# loop3 是新生成的 event loop,然而并非以后 context 的默认 event loop
>>>
>>> loop3.stop()
>>> loop3.is_closed()
False
>>> loop3.run_until_complete(main(loop, 'loop.run_until_complete'))
loop.run_until_complete : not match
Current running loop is :140127033794456
# stop 一个 event loop 只是暂停 event loop , 还能再用。>>>
>>> asyncio.set_event_loop(None)
>>> loop5 = asyncio.get_event_loop()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/shone/miniconda2/envs/python37/lib/python3.7/asyncio/events.py", line 644, in get_event_loop
    % threading.current_thread().name)
RuntimeError: There is no current event loop in thread 'MainThread'
# 调用 set_event_loop(None) 后,执行 get_event_loop 会产生例外,>>>
>>> loop6 = asyncio.new_event_loop()
>>> asyncio.set_event_loop(loop6)
>>> loop7 = asyncio.get_event_loop()
>>> loop6 is loop7
True
# 此时须要给以后 context 再 set 一个 event loop 才行
>>>
>>> loop4.run_until_complete(main(loop6, 'loop.run_until_complete'))
loop.run_until_complete : not match
Current running loop is :140127033408816
# 一个 context 中能够生成多个 event loop,然而默认的 event loop 只有一个。并且,只有 event loop 不被 close(), 任何一个 event loop 都能 run,然而正 running 的 event loop 只有一个
>>>
>>> asyncio.run(main(loop6, 'asyncio.run'))
asyncio.run : not match
Current running loop is :140127033529008
>>> loop8 = asyncio.get_event_loop()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/shone/miniconda2/envs/python37/lib/python3.7/asyncio/events.py", line 644, in get_event_loop
    % threading.current_thread().name)
RuntimeError: There is no current event loop in thread 'MainThread'.
# 调用 asyncio.run()相当于从新设定以后 contex 的默认 loop , 应用完后,close 以后的默认 loop
>>>

以上代码实例,起源自

https://gist.github.com/kaelz…
https://www.programcreek.com/…

正文完
 0