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

时间:2017-09-07 09:50:25

标签: python multithreading python-asyncio

我有一个简单的测试,我使用Dim startRow As Long Dim endRow As Long With OP_wb.Worksheets("Optic Main") startRow = .Range("F2").End(xlDown).Row endRow = .Columns("F").Find(What:="BBSE", LookIn:=xlValues, LookAt:=xlWhole).Row .Rows(startRow & ":" & endRow).Cut End With With Demand_WB.Worksheets("Illuminators") .Range("A" & .Rows.Count).End(xlUp).Offset(1).Insert Shift:=xlDown End With 方法运行Python asyncio事件循环,然后立即在另一个线程中停止它。但是,事件循环似乎没有终止。我有以下测试用例:

run_forever

此测试用例打印:

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!')

因此,测试似乎在Started! Requested stop! 上阻塞,等待事件循环终止。

如果我转储我的主题,我会得到以下内容:

thread.join()

我没有深入研究Python代码,但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 似乎在等待工作。我想这个问题可能会发生,因为我已经调用了selectors.py而事件循环没有更多工作,但这似乎是一个非常有问题的限制。

或者我可能误解了这应该如何运作?

1 个答案:

答案 0 :(得分:11)

关于事件循环类的文档says

  

此类不是线程安全的。

further

  

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

loop.call_soon_threadsafe(callback, *args)

似乎是我们需要的:

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!')

打印:

Started!
Requested stop!
Finished!