Python Can';无法通过asyncio.run\u coroutine\u threadsafe等待

Python Can';无法通过asyncio.run\u coroutine\u threadsafe等待,python,python-asyncio,Python,Python Asyncio,我注意到asyncio.run\u coroutine\u threadsafe函数不接受一般的等待对象,我不理解这种限制的原因。观察 导入异步IO 异步def native_coro(): 返回 @异步协同程序 基于def生成器的def coro(): 返回 等待上课: 定义等待(自我): 返回asyncio.Future() loop=asyncio.get\u event\u loop() asyncio.run_coroutine_threadsafe(native_coro(),loo

我注意到
asyncio.run\u coroutine\u threadsafe
函数不接受一般的等待对象,我不理解这种限制的原因。观察

导入异步IO
异步def native_coro():
返回
@异步协同程序
基于def生成器的def coro():
返回
等待上课:
定义等待(自我):
返回asyncio.Future()
loop=asyncio.get\u event\u loop()
asyncio.run_coroutine_threadsafe(native_coro(),loop)
asyncio.run\u coroutine\u threadsafe(基于生成器的\u coro(),循环)
asyncio.run\u coroutine\u threadsafe(waitiable(),循环)
在Python3.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\u coroutine\u threadsafe

我的问题是:

  • 这项限制的原因是什么
  • 上面定义的
    wrapper
    函数是否是传递可等待的
    运行\u coroutine\u threadsafe
    和其他需要
    异步def
    或生成器定义的coroutine的API的最传统方法
  • 这项限制的原因是什么

    从这个角度来看,原因当然不是技术性的。由于代码已经调用了
    sure\u future
    (而不是说,
    create\u task
    ),它将自动在任何可等待的对象上工作,并且工作正常

    限制的原因可以在跟踪器上找到。该功能是在2015年增加的,这是由于。在对相关问题的讨论中,提交人明确要求将该功能重命名为
    确保未来线程安全
    (与
    确保未来
    )并接受尤里·塞利万诺夫(Yury Selivanov)支持的任何形式的等待。然而,Guido的想法是:

    我反对那个想法。不管怎样,我都不认为这种方法有着重要的未来:它只是线程和异步世界之间的一点粘合剂,人们将通过找到一个示例来学习如何使用它

    [……]

    但老实说,我不想鼓励在线程和事件循环之间来回翻转;我认为这是一种必然的罪恶。我们目前拥有的名称来自于一个在线程世界中编码的人的观点,他想把一些东西交给asyncio世界

    为什么线程世界中的某个人需要等待asyncio.future?这听起来像是他们在混淆这两个世界——或者他们应该编写异步IO代码而不是线程代码

    还有其他类似的评论,但上面的内容基本上概括了这一论点

    上面定义的
    wrapper
    函数是否是传递可等待的
    运行\u coroutine\u threadsafe
    和其他需要异步def或生成器定义的coroutine的API的最传统方式

    如果您确实需要一个协程对象,那么像
    wrapper
    这样的东西肯定是一种简单而正确的方法

    如果创建包装器的唯一原因是调用
    run\u coroutine\u threadsafe
    ,但实际上您对结果或
    run\u coroutine\u threadsafe
    返回的
    concurrent.futures.Future
    不感兴趣,可以通过直接调用
    call\u soon\u threadsafe
    避免包装:

    loop.call_soon_threadsafe(asyncio.ensure_future, awaitable)
    

    放得好。为了举例说明为什么“线程世界中的某个人会有一个他们需要等待的[Waitable],我正在测试一个websocket服务器,我有多个客户端同时执行使用Robot框架执行的测试步骤。没有对执行上下文的控制意味着我无法使其全部异步。在我的情况下,我确实关心并发的.futures.Future,但用于
    asyncio。确保将来的
    在其他地方很方便。@ChrisHunt我听到了。在我看来,
    run\u coroutine\u threadsafe
    (和
    run\u in\u executor
    在另一个方向)提供的功能是asyncio和经典同步/线程代码之间的奇妙粘合剂,对于将asyncio引入现有代码库非常重要。不幸的是,它被低估了,在asyncio介绍材料中经常被忽略。我理解其意图是鼓励尽可能多的代码成为“本地”基于协同程序的代码,但这不可能在一夜之间实现,在实现之前,需要有一种方便的方式让两者进行互操作。
    loop.call_soon_threadsafe(asyncio.ensure_future, awaitable)