我正在使用异步编程,并根据此线程中的一些想法编写了一个小包装类,用于线程安全执行协同例程:python asyncio, how to create and cancel tasks from another thread。经过一些调试后,我发现它在调用Thread类的join()函数时挂起(我只是为了测试而覆盖它)。想到我犯了一个错误,我基本上复制了OP所说的代码,并对其进行了测试以找到同样的问题。
他轻微改动的代码:
import threading
import asyncio
from concurrent.futures import Future
import functools
class EventLoopOwner(threading.Thread):
class __Properties:
def __init__(self, loop, thread, evt_start):
self.loop = loop
self.thread = thread
self.evt_start = evt_start
def __init__(self):
threading.Thread.__init__(self)
self.__elo = self.__Properties(None, None, threading.Event())
def run(self):
self.__elo.loop = asyncio.new_event_loop()
asyncio.set_event_loop(self.__elo.loop)
self.__elo.thread = threading.current_thread()
self.__elo.loop.call_soon_threadsafe(self.__elo.evt_start.set)
self.__elo.loop.run_forever()
def stop(self):
self.__elo.loop.call_soon_threadsafe(self.__elo.loop.stop)
def _add_task(self, future, coro):
task = self.__elo.loop.create_task(coro)
future.set_result(task)
def add_task(self, coro):
self.__elo.evt_start.wait()
future = Future()
p = functools.partial(self._add_task, future, coro)
self.__elo.loop.call_soon_threadsafe(p)
return future.result() # block until result is available
def cancel(self, task):
self.__elo.loop.call_soon_threadsafe(task.cancel)
async def foo(i):
return 2 * i
async def main():
elo = EventLoopOwner()
elo.start()
task = elo.add_task(foo(10))
x = await task
print(x)
elo.stop(); print("Stopped")
elo.join(); print("Joined") # note: giving it a timeout does not fix it
if __name__ == "__main__":
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
assert isinstance(loop, asyncio.AbstractEventLoop)
try:
loop.run_until_complete(main())
finally:
loop.close()
我运行它的时间大约有50%,它只是拖延并说“停止”#34;但不是"加入"。我做了一些调试,发现它与Task本身发送异常的时间相关。这并不是每次都会发生,但由于它是在我调用threading.Thread.join()
时发生的,我必须假设它与循环的破坏有关。可能导致这种情况的原因是什么?
例外情况就是:"cannot join current thread"
告诉我.join()
有时 在我调用它的线程上运行有时来自ELO主题。
发生了什么,我该如何解决?
我正在使用Python 3.5.1。
注意:这不会在IDE One上复制:http://ideone.com/0LO2D9