简体   繁体   English

来自 asyncio.run_coroutine_threadsafe 的未来永远挂起?

[英]Future from asyncio.run_coroutine_threadsafe hangs forever?

As a followup to my previous question about calling an async function from a synchronous one , I've discovered asyncio.run_coroutine_threadsafe .作为我之前关于从同步函数调用异步函数的问题的后续,我发现了asyncio.run_coroutine_threadsafe

On paper, this looks ideal.在纸面上,这看起来很理想。 Based on the comments in this StackOverflow question , this looks ideal.根据此 StackOverflow question 中的评论,这看起来很理想。 I can create a new Thread, get a reference to my original event loop, and schedule the async function to run inside the original event loop while only blocking the new Thread.我可以创建一个新线程,获取对原始事件循环的引用,并安排异步函数在原始事件循环内运行,同时仅阻塞新线程。

class _AsyncBridge:
    def call_async_method(self, function, *args, **kwargs):
        print(f"call_async_method {threading.get_ident()}")
        event_loop = asyncio.get_event_loop()
        thread_pool = ThreadPoolExecutor()
        return thread_pool.submit(asyncio.run, self._async_wrapper(event_loop, function, *args, **kwargs)).result()

    async def _async_wrapper(self, event_loop, function, *args, **kwargs):
        print(f"async_wrapper {threading.get_ident()}")
        future = asyncio.run_coroutine_threadsafe(function(*args, **kwargs), event_loop)
        return future.result()

This doesn't error, but it doesn't ever return, either.这不会出错,但也不会返回。 The Futures just hang and the async call is never hit.期货只是挂起,异步调用永远不会被命中。 It doesn't seem to matter whether I use a Future in call_async_method , _async_wrapper , or both;我是否在call_async_method_async_wrapper或两者中使用 Future 似乎并不重要; wherever I use a Future, it hangs.无论我在哪里使用 Future,它都会挂起。

I experimented with putting the run_coroutine_threadsafe call directly in my main event loop:我尝试将run_coroutine_threadsafe调用直接放在我的主事件循环中:

event_loop = asyncio.get_event_loop()
future = asyncio.run_coroutine_threadsafe(cls._do_work_async(arg1, arg2, arg3), event_loop)
return_value = future.result()

Here too, the Future hangs.在这里,未来也悬而未决。

I tried using the LoopExecutor class defined here , which seems like the exact answer to my needs.我尝试使用此处定义的LoopExecutor类,这似乎是我需要的确切答案。

event_loop = asyncio.get_event_loop()
loop_executor = LoopExecutor(event_loop)
future = loop_executor.submit(cls._do_work_async, arg1=arg1, arg2=arg2, arg3=arg3)
return_value = future.result()

There too, the returned Future hangs.在那里,返回的 Future 也挂了。

I toyed with the idea that I was blocking my original event loop and therefore the scheduled task would never run, so I made a new event loop:我想我会阻塞我原来的事件循环,因此计划任务永远不会运行,所以我做了一个新的事件循环:

event_loop = asyncio.get_event_loop()
new_event_loop = asyncio.new_event_loop()
print(event_loop == new_event_loop) # sanity check to make sure the new loop is actually different from the existing one - prints False as expected
loop_executor = LoopExecutor(new_event_loop)
future = loop_executor.submit(cls._do_work_async, arg1=arg1, arg2=arg2, arg3=arg3)
return_value = future.result()
return return_value

Still hanging at future.result() and I don't understand why.仍然挂在future.result() ,我不明白为什么。

What's wrong with asyncio.run_coroutine_threadsafe /the way I'm using it? asyncio.run_coroutine_threadsafe /我使用它的方式有什么问题?

I think there are two problems. 我认为有两个问题。 First one is that run_coroutine_threadsafe only submit the coroutine but not really run it. 第一个是run_coroutine_threadsafe仅提交协程而不真正运行它。

So 所以

event_loop = asyncio.get_event_loop()
future = asyncio.run_coroutine_threadsafe(cls._do_work_async(arg1, arg2, arg3), event_loop)
return_value = future.result()

doesn't work as you've never run this loop. 无法运行,因为您从未运行过此循环。

To make it work, theoretically, you can just use asyncio.run(future) , but actually, you cannot, maybe it is because that it is submitted by run_coroutine_threadsafe . 要使其工作,从理论上讲,您可以只使用asyncio.run(future) ,但是实际上,您不能,也许是因为它是由run_coroutine_threadsafe提交的。 The following will work: 以下将起作用:

import asyncio

async def stop():
    await asyncio.sleep(3)

event_loop = asyncio.get_event_loop()
coro = asyncio.sleep(1, result=3)
future = asyncio.run_coroutine_threadsafe(coro, event_loop)
event_loop.run_until_complete(stop())
print(future.result())

The second problem is, I think you have noticed that your structure is somehow reversed. 第二个问题是,我认为您已经注意到您的结构有所改变。 You should run the event loop in the separated thread but submit the task from the main thread. 您应该在单独的线程中运行事件循环,但要从主线程提交任务。 If you submit it in the separated thread, you still need to run the event loop in the main thread to actually execute it. 如果在单独的线程中提交它,则仍然需要在主线程中运行事件循环才能实际执行它。 Mostly I would suggest just create another event loop in the separated thread. 通常,我建议只在单独的线程中创建另一个事件循环。

I have run into the same issue, and the answer by @Sraw did not help me, as in my case the coroutine also had to be done in the main event loop, monopolized by the async library.我遇到了同样的问题,@Sraw 的回答对我没有帮助,因为在我的情况下,协程也必须在主事件循环中完成,由异步库独占。

As a quick (though admittedly hacky) approach, what helped me is the nest_asyncio library, which patches asyncio to allow nested event loops.作为一种快速(虽然公认是 hacky)的方法,帮助我的是nest_asyncio库,它修补了asyncio以允许嵌套事件循环。

With it, the following works for me, even if the event loop is already running:有了它,即使事件循环已经在运行,以下内容也适用于我:

import asyncio
import nest_asyncio
nest_asyncio.apply()

event_loop = asyncio.get_event_loop()
coro = asyncio.sleep(1, result=3)
print(event_loop.run_until_complete(coro))

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

相关问题 无法将 awaitable 传递给 asyncio.run_coroutine_threadsafe - Can't pass awaitable to asyncio.run_coroutine_threadsafe Python Asyncio 没有使用 asyncio.run_coroutine_threadsafe 运行新的协程 - Python Asyncio is not running new coroutine using asyncio.run_coroutine_threadsafe Python asyncio loop.create_task 和 asyncio.run_coroutine_threadsafe 的区别 - Python asyncio difference between loop.create_task and asyncio.run_coroutine_threadsafe Python asyncio run_coroutine_threadsafe永不运行协程? - Python asyncio run_coroutine_threadsafe never running coroutine? 如何正确使用 asyncio run_coroutine_threadsafe 函数? - How to properly use asyncio run_coroutine_threadsafe function? 需要 Future 或协程 - asyncio - A Future or coroutine is required - asyncio Python unittest + asyncio 永远挂起 - Python unittest + asyncio hangs forever Asyncio python - TypeError: A Future, a coroutine or an awaitable is required - Asyncio python - TypeError: A Future, a coroutine or an awaitable is required loop.run_until_complete 给出“TypeError: An asyncio.Future, a coroutine or an awaitable is required” - loop.run_until_complete gives “TypeError: An asyncio.Future, a coroutine or an awaitable is required” 类型错误:需要 asyncio.Future、协程或 awaitable - TypeError: An asyncio.Future, a coroutine or an awaitable is required
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM