从另一个线程调度asyncio协程,没有一堆回调和同步等待

时间:2016-10-31 11:50:45

标签: python multithreading asynchronous python-asyncio

我必须要求澄清this问题。

我有一个发送消息的协程send。我想在loop1(在线程1中运行)loop2(在线程2中运行)中安排它:

async def send_threadsafe(self, message, current_loop=loop2, dest_loop=loop1):
    future = asyncio.run_coroutine_threadsafe(
        send(message), loop=dest_loop
    )

future返回的asyncio.run_coroutine_threadsafeconcurrent.futures.Future,无法异步等待。

所以问题是:我如何正确等待future和/或我应该如何安排我的send来获得一个等待的对象?

我知道我能做到:

async def send_threadsafe(...):
    future = ...
    result = await current_loop.run_in_executor(None, future.result)

但有没有办法在不使用其他线程的情况下完成?因为run_in_executor会将future.result发送到线程池而我不想使用该线程池。

我不想使用call_soon_threadsafe的原因是它需要创建多个回调。首先,安排在send中运行loop1。其次,在send中运行loop1并在loop2中安排第三次回调。第三,将结果设置为在第一个回调中创建的未来(因为asyncio期货不是线程安全的,我不能设置loop1的结果)。

1 个答案:

答案 0 :(得分:4)

您可以使用asyncio.wrap_future从并发的未来获得asyncio的未来:

async def send_threadsafe(self, message, destination, *, loop=loop):
    concurrent = asyncio.run_coroutine_threadsafe(
        send(message), loop=destination)
    return await asyncio.wrap_future(concurrent, loop=loop)

通过实现asyncio执行器可以实现相同的目的:

from concurrent.futures import Executor

class AsyncioExecutor(Executor):

    def __init__(self, loop):
        self.loop = loop

    def submit(self, fn, *args, **kwargs):
        coro = fn(*args, **kwargs)
        return asyncio.run_coroutine_threadsafe(coro, self.loop)

示例:

executor = AsyncioExecutor(remote_loop)
result = await loop.run_in_executor(executor, send, message)