Python asyncio:当调用stop方法时,事件循环似乎没有停止

Nei*_*eil 10 python multithreading python-asyncio

我有一个简单的测试,我使用该run_forever方法运行Python asyncio事件循环,然后立即在另一个线程中停止它.但是,事件循环似乎没有终止.我有以下测试用例:

import asyncio
from threading import Thread

loop = asyncio.get_event_loop()
thread = Thread(target=loop.run_forever)
thread.start()
print('Started!')
loop.stop()
print('Requested stop!')
thread.join()
print('Finished!')
Run Code Online (Sandbox Code Playgroud)

此测试用例打印:

Started!
Requested stop!
Run Code Online (Sandbox Code Playgroud)

因此,测试似乎阻塞thread.join(),等待事件循环终止.

如果我转储我的线程,我得到以下内容:

Thread 0x00007000087ec000 (most recent call first):
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/selectors.py", line 577 in select
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/asyncio/base_events.py", line 1388 in _run_once
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/asyncio/base_events.py", line 421 in run_forever
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/threading.py", line 862 in run
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/threading.py", line 914 in _bootstrap_inner
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/threading.py", line 882 in _bootstrap

Current thread 0x00007fffc6b273c0 (most recent call first):
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/threading.py", line 1070 in _wait_for_tstate_lock
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/threading.py", line 1054 in join
Run Code Online (Sandbox Code Playgroud)

我没有深入研究Python代码,但selectors.py似乎在等待工作.我想这个问题可能正在发生,因为我已经调用了,stop而事件循环没有更多的工作,所以这似乎是一个非常有问题的限制.

或许我误解了这应该如何运作?

Mik*_*mov 15

文档关于事件循环类:

这个类不是线程安全的.

进一步:

事件循环在线程中运行,并在同一线程中执行所有回调和任务.[...]要从不同的线程安排回调,应使用AbstractEventLoop.call_soon_threadsafe()方法.例:

loop.call_soon_threadsafe(callback, *args)
Run Code Online (Sandbox Code Playgroud)

似乎是我们需要的:

import asyncio
from threading import Thread

loop = asyncio.get_event_loop()
thread = Thread(target=loop.run_forever)
thread.start()
print('Started!')
loop.call_soon_threadsafe(loop.stop)  # here
print('Requested stop!')
thread.join()
print('Finished!')
Run Code Online (Sandbox Code Playgroud)

打印:

Started!
Requested stop!
Finished!
Run Code Online (Sandbox Code Playgroud)

  • 那太好了,谢谢。asyncio API 在某些地方有点不直观!你不可能从与正在运行的事件循环相同的线程中调用 `stop`,但是当你从不同的线程调用时它不起作用,而不使用 `call_soon_threadsafe`。 (3认同)
  • 是的,您肯定可以从与正在运行的事件循环相同的线程中调用 `stop`——从正在该事件循环上运行的任务执行此操作。 (2认同)