简体   繁体   English

立即从同步代码执行异步回调

[英]Execute async callback from synchronous code immediately

Problem 问题

I have a library which currently has no async support and needs to be called from async code. 我有一个目前不支持异步的库,需要从异步代码中调用。 The async code calls into the library through a handler ( handler function in the code below). 异步代码通过处理程序(下面的代码中的处理handler函数)调用库。 While the handler executed, the library periodically calls a callback ( callback_wrapper ) to report progress. 在执行处理程序时,库会定期调用回调( callback_wrapper )以报告进度。

The synchronous handler is executed in a ThreadPoolExecutor in order for the main event loop to be able to process further events while the handler is running. 同步处理程序在ThreadPoolExecutor中执行,以便主事件循环能够在处理程序运行时处理其他事件。

What happens is that the synchronous callback is executed immediately, but the async callback is only executed after the main handler has executed. 发生的情况是立即执行同步回调,但是异步回调仅在主处理程序执行后执行。 The desired result is the async callbacks to be executed immediately. 理想的结果是立即执行异步回调。

I guess the event loop is blocked at the run_in_executor call, but I am not sure how to resolve this. 我猜想事件循环在run_in_executor调用中被阻止,但是我不确定如何解决这个问题。

Code

import asyncio
import time
from concurrent.futures.thread import ThreadPoolExecutor

loop = asyncio.get_event_loop()


def handler():
    print('handler started')
    callback_wrapper()
    time.sleep(1)
    print('handler stopped')


async def callback():
    print('callback')


def callback_wrapper():
    print('callback wrapper started')
    asyncio.ensure_future(callback(), loop=loop)
    print('callback wrapper stopped')


async def main():
    handler()


with ThreadPoolExecutor() as pool:
    async def thread_handler():
        await loop.run_in_executor(pool, handler)


    loop.run_until_complete(main())

Output 输出量

handler started
callback wrapper started
callback wrapper stopped
handler stopped
callback

Desired Output 期望的输出

handler started
callback wrapper started
callback
callback wrapper stopped
handler stopped

thanks to @user4815162342's input, I came up the the following solution: 感谢@ user4815162342的输入,我提出了以下解决方案:

import asyncio
import time
from concurrent.futures.thread import ThreadPoolExecutor

loop = asyncio.get_event_loop()


def handler():
    print('handler started')
    callback_wrapper()
    time.sleep(1)
    print('handler stopped')


async def callback():
    print('callback')


def callback_wrapper():
    print('callback wrapper started')
    asyncio.run_coroutine_threadsafe(callback(), loop).result()
    print('callback wrapper stopped')


async def main():
    await thread_handler()


with ThreadPoolExecutor() as pool:
    async def thread_handler():
        await loop.run_in_executor(pool, handler)


    loop.run_until_complete(main())

which produces the desired result: 产生预期的结果:

handler started
callback wrapper started
callback
callback wrapper stopped
handler stopped

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM