【发布时间】:2019-04-09 00:45:23
【问题描述】:
我有一个带有一个主线程的程序,我在其中生成了第二个使用 asyncio 的线程。是否提供了任何工具来同步这两个线程?如果一切都是异步的,我可以用它的同步原语来做,例如:
import asyncio
async def taskA(lst, evt):
print(f'Appending 1')
lst.append(1)
evt.set()
async def taskB(lst, evt):
await evt.wait()
print('Retrieved:', lst.pop())
lst = []
evt = asyncio.Event()
asyncio.get_event_loop().run_until_complete(asyncio.gather(
taskA(lst, evt),
taskB(lst, evt),
))
但是,这不适用于多线程。如果我只使用threading.Event,那么它将阻塞异步线程。我想我可以将等待推迟到执行人:
import asyncio
import threading
def taskA(lst, evt):
print(f'Appending 1')
lst.append(1)
evt.set()
async def taskB(lst, evt):
asyncio.get_event_loop().run_in_executor(None, evt.wait)
print('Retrieved:', lst.pop())
def targetA(lst, evt):
taskA(lst, evt)
def targetB(lst, evt):
asyncio.set_event_loop(asyncio.new_event_loop())
asyncio.get_event_loop().run_until_complete(taskB(lst, evt))
lst = []
evt = threading.Event()
threadA = threading.Thread(target=targetA, args=(lst, evt))
threadB = threading.Thread(target=targetB, args=(lst, evt))
threadA.start()
threadB.start()
threadA.join()
threadB.join()
但是,让执行线程只等待互斥锁似乎不自然。这是应该这样做的方式吗?或者有没有其他方法可以异步等待操作系统线程之间的同步?
【问题讨论】:
-
在 taskB 中等待
asyncio.Event,然后使用loop.call_soon_threadsafe从 taskA 设置它。 -
@user4815162342 这是一个合理的选择。感觉有点像我在颠倒逻辑,理想情况下我希望主线程不必直接处理另一个线程的异步循环,但是是的,这可能适用于我认为的情况。
-
@user4815162342 我用你的建议解决了我的问题。因为我想要“函数语义”(在主线程中处理这些数据并返回一些结果),所以我使用
queue.Queue将期货从 asyncio 线程发送到主线程,并使用call_soon_threadsafe从主线程。随意发布它作为接受的答案。 -
为此目的使用futures绝对是要走的路——理想情况下taskB会创建两个future,一个
concurrent.futures和一个asyncio,然后连接它们,将并发发送给taskA,然后等待异步的。run_in_executor实现了相当通用的未来链接,可以为此重用,但我不确定其中是否是公开的。 -
我现在已经发布了带有原始评论的答案,但也是一种替代方法,它应该消除对显式队列的需求。
标签: python multithreading synchronization python-asyncio