我正在尝试在Python中实现一个简单的actor系统,以便对并发编程有所了解。
我主要关心的是使用asyncio
模块在Python中编写期货的一般任务。
假设我有一个在单独的线程上运行的事件循环。
import asyncio
from threading import Thread
loop = asyncio.new_event_loop()
def run_event_loop(loop):
asyncio.set_event_loop(loop)
loop.run_forever()
t = Thread(target=run_event_loop, args=(loop,))
t.start()
为了避免同步通信,我需要能够以某种方式编写Futures
。举一个简单的例子,假设我要合并两个async
协程的结果。
我的第一次(显然是错误的)尝试:
async def f(x):
fut = asyncio.run_coroutine_threadsafe(g(x / 2), loop)
return fut
async def g(x):
return x * 2
f(x) = x / 2
g(x) = x * 2
f(g(x)) = x
我无法得出一个干净的解决方案来解决以下一般问题:
x = 10
future = asyncio.run_coroutine_threadsafe(f(x), loop)
print(future) # <Future at 0x106f797f0 state=pending>
print(future.result()) # <Future at 0x10677c780 state=finished returned float>
print(future.result().result()) # 10.0
理想情况下,我应该合并期货并在最后执行一个future.result()
。也许我正在错误地考虑所有这些。
答案 0 :(得分:3)
这里的根本问题是:
fut = asyncio.run_coroutine_threadsafe(g(x / 2), loop)
您在async
函数内部,并尝试在同一线程的同一事件循环中运行另一个异步函数。您不需要run_coroutine_threadsafe
;只是await
。
如果您仍然致电run_coroutine_threadsafe
会怎样?然后您得到的是concurrent.futures.Future
。正如asyncio
文档顶部所解释的,这与asnycio.Future
并不是一回事,后者旨在模仿并发的未来,但在幕后却是一个不同的事。您可以组成两个asyncio期货(来自同一事件循环),可以组成两个并发的期货,但不能与asyncio的未来组成一个并发的期货。
您可以将一个并发的future包装在一个异步的future中(直接使用wrap_future
,或更常见的是间接使用run_in_executor
)。但是接下来您将要面对的是并发未来,它包含了一个异步将来,该异步远期包装了一个并发未来,但仍然无法组成。