[英]Can't pass awaitable to asyncio.run_coroutine_threadsafe
I have observed that the asyncio.run_coroutine_threadsafe
function does not accept general awaitable objects, and I do not understand the reason for this restriction.我观察到
asyncio.run_coroutine_threadsafe
函数不接受一般的可等待对象,我不明白这个限制的原因。 Observe观察
import asyncio
async def native_coro():
return
@asyncio.coroutine
def generator_based_coro():
return
class Awaitable:
def __await__(self):
return asyncio.Future()
loop = asyncio.get_event_loop()
asyncio.run_coroutine_threadsafe(native_coro(), loop)
asyncio.run_coroutine_threadsafe(generator_based_coro(), loop)
asyncio.run_coroutine_threadsafe(Awaitable(), loop)
Running this with Python 3.6.6 yields使用 Python 3.6.6 运行它会产生
Traceback (most recent call last):
File "awaitable.py", line 24, in <module>
asyncio.run_coroutine_threadsafe(Awaitable(), loop)
File "~/.local/python3.6/lib/python3.6/asyncio/tasks.py", line 714, in run_coroutine_threadsafe
raise TypeError('A coroutine object is required')
TypeError: A coroutine object is required
where line 24 is asyncio.run_coroutine_threadsafe(Awaitable(), loop)
.其中第 24 行是
asyncio.run_coroutine_threadsafe(Awaitable(), loop)
。
I know I can wrap my awaitable object in a coroutine defined like我知道我可以将我的可等待对象包装在一个定义如下的协程中
awaitable = Awaitable()
async def wrapper():
return await awaitable
asyncio.run_coroutine_threadsafe(wrapper(), loop)
however my expectation was that the awaitable would be a valid argument directly to run_coroutine_threadsafe
.但是我的期望是 awaitable 将直接成为
run_coroutine_threadsafe
的有效参数。
My questions are:我的问题是:
wrapper
function defined above the most conventional way to pass an awaitable to run_coroutine_threadsafe
and other APIs that demand an async def
or generator-defined coroutine?wrapper
函数是将可等待run_coroutine_threadsafe
传递给run_coroutine_threadsafe
和其他需要async def
定义或生成器定义的协程的 API 的最传统方法吗?What is the reason for this restriction?
这个限制的原因是什么?
Looking at the implementation , the reason is certainly not technical.从实现来看,原因肯定不是技术上的。 Since the code already invokes
ensure_future
(rather than, say, create_task
), it would automatically work, and work correctly, on any awaitable object.由于代码已经调用了
ensure_future
(而不是,比如说create_task
),它会自动工作,并在任何可等待的对象上正常工作。
The reason for the restriction can be found on the tracker.限制的原因可以在跟踪器上找到。 The function was added in 2015 as a result of a pull request .
作为pull request的结果,该功能于 2015 年添加。 In the discussion on the related bpo issue the submitter explicitly requests the function be renamed to
ensure_future_threadsafe
(in parallel to ensure_future
) and accept any kind of awaitable, a position seconded by Yury Selivanov.在有关bpo 问题的讨论中,提交者明确要求将函数重命名为
ensure_future_threadsafe
(与ensure_future
并行)并接受任何类型的 awaitable,这是 Yury Selivanov 附议的立场。 However, Guido was against the idea:然而,Guido反对这个想法:
I'm against that idea.
我反对这种想法。 I don't really see a great important future for this method either way: It's just a little bit of glue between the threaded and asyncio worlds, and people will learn how to use it by finding an example.
无论哪种方式,我都没有真正看到这种方法的重要未来:它只是线程和异步世界之间的一点胶水,人们将通过查找示例来学习如何使用它。
[...]
[...]
But honestly I don't want to encourage flipping back and forth between threads and event loops;
但老实说,我不想鼓励线程和事件循环之间来回翻转; I see it as a necessary evil.
我认为这是一种必要的罪恶。 The name we currently have is fine from the POV of someone coding in the threaded world who wants to hand off something to the asyncio world.
我们目前拥有的名字来自一个在线程世界中编码的人的 POV,他想将某些东西交给 asyncio 世界。
Why would someone in the threaded world have an asyncio.future that they need to wait for?
为什么线程世界中的某个人会有一个他们需要等待的 asyncio.future ? That sounds like they're mixing up the two worlds -- or they should be writing asyncio code instead of threaded code.
这听起来像是他们混淆了两个世界——或者他们应该编写异步代码而不是线程代码。
There are other comments in a similar vein, but the above pretty much sums up the argument.还有其他类似的评论,但上面几乎总结了这个论点。
Is the
wrapper
function defined above the most conventional way to pass an awaitable torun_coroutine_threadsafe
and other APIs that demand an async def or generator-defined coroutine?上面定义的
wrapper
函数是将可等待run_coroutine_threadsafe
传递给run_coroutine_threadsafe
和其他需要异步定义或生成器定义的协程的 API 的最传统方法吗?
If you actually need a coroutine object, something like wrapper
is certainly a straightforward and correct way to get one.如果您确实需要一个协程对象,那么像
wrapper
东西肯定是一种直接且正确的获取方式。
If the only reason you're creating the wrapper is to call run_coroutine_threadsafe
, but you're not actually interested in the result or the concurrent.futures.Future
returned by run_coroutine_threadsafe
, you can avoid the wrapping by calling call_soon_threadsafe
directly:如果您创建包装器的唯一原因是调用
run_coroutine_threadsafe
,但您实际上对结果或run_coroutine_threadsafe
返回的concurrent.futures.Future
不感兴趣,则可以通过直接调用call_soon_threadsafe
来避免包装:
loop.call_soon_threadsafe(asyncio.ensure_future, awaitable)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.