用Python编写期货(asyncio)

时间:2018-07-09 21:07:50

标签: python concurrency python-asyncio

我正在尝试在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()。也许我正在错误地考虑所有这些。

1 个答案:

答案 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)。但是接下来您将要面对的是并发未来,它包含了一个异步将来,该异步远期包装了一个并发未来,但仍然无法组成。