Chr*_*unt 3 python python-asyncio
我观察到该asyncio.run_coroutine_threadsafe函数不接受一般的可等待对象,我不明白这种限制的原因。观察
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)
Run Code Online (Sandbox Code Playgroud)
使用 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
Run Code Online (Sandbox Code Playgroud)
第 24 行在哪里asyncio.run_coroutine_threadsafe(Awaitable(), loop)。
我知道我可以将我的可等待对象包装在一个定义如下的协程中
awaitable = Awaitable()
async def wrapper():
return await awaitable
asyncio.run_coroutine_threadsafe(wrapper(), loop)
Run Code Online (Sandbox Code Playgroud)
但是我的期望是 awaitable 将是直接到run_coroutine_threadsafe.
我的问题是:
wrapper上面定义的函数是将awaitable 传递给run_coroutine_threadsafe其他需要async def或生成器定义的协程的API的最传统方式吗?这个限制的原因是什么?
从实现来看,原因肯定不是技术上的。由于代码已经调用ensure_future(而不是,比如说,create_task),它会自动工作,并在任何可等待对象上正常工作。
限制的原因可以在跟踪器上找到。作为pull request的结果,该功能是在 2015 年添加的。在有关bpo 问题的讨论中,提交者明确要求将函数重命名为ensure_future_threadsafe(与 并行ensure_future)并接受任何类型的 awaitable,这是 Yury Selivanov 附议的立场。然而,Guido反对这个想法:
我反对这种想法。无论哪种方式,我都没有真正看到这种方法的重要未来:它只是线程和异步世界之间的一点胶水,人们将通过查找示例来学习如何使用它。
[...]
但老实说,我不希望鼓励线程和事件循环之间来回翻转; 我认为这是一种必要的罪恶。我们目前拥有的名字来自一个在线程世界中编码的人的 POV,他想将某些东西交给 asyncio 世界。
为什么线程世界中的某个人会有一个他们需要等待的 asyncio.future ?这听起来像是他们混淆了两个世界——或者他们应该编写异步代码而不是线程代码。
还有其他类似的评论,但上面几乎总结了这个论点。
wrapper上面定义的函数是将可等待对象run_coroutine_threadsafe和其他需要异步定义或生成器定义的协程的 API传递的最传统方式吗?
如果您确实需要一个协程对象,那么像这样的东西wrapper肯定是一种直接且正确的获取方式。
如果您创建包装器的唯一原因是调用run_coroutine_threadsafe,但您实际上对结果或concurrent.futures.Future返回的不感兴趣,则run_coroutine_threadsafe可以通过call_soon_threadsafe直接调用来避免包装:
loop.call_soon_threadsafe(asyncio.ensure_future, awaitable)
Run Code Online (Sandbox Code Playgroud)