【问题标题】:asyncio: how to combine sync code without forcing full exposure to asyncioasyncio:如何在不强制完全暴露于 asyncio 的情况下组合同步代码
【发布时间】:2019-03-08 20:22:50
【问题描述】:

python 的 asyncio 似乎是一种孤注一掷的交易。具体来说,它似乎强制完整的调用堆栈是异步感知的。

这是一个例子:

假设有一个由函数a()实现的算法。
该算法调用函数b()

def a(b):
  for i in ...:
    # do smth...
    res = b()
    # do smth more ...

现在让我们假设函数 b() 可能在不同的环境中以不同的方式实现,并且可能希望在异步事件循环中调用 a()(使用 loop.call_soon()) 和 b() 调用一些异步代码:

def b():
   await .... # this forces b() to be declared async.

似乎明确禁止使用现有的事件循环... 那么,是否有方法可以在不强制将完整堆栈(a()b())显式定义为异步协程的情况下实现此功能?

【问题讨论】:

  • It seems that python's asyncio is an all-or-nothing kind of deal. Specifically it seems to force full call stack to be async-aware. -- 是的。所有async 的栈都是这样的。
  • Gevent 提供了更多的灵活性。我喜欢它的一点是,您不必编写异步代码来使其异步。特别是 WSGI 的东西。只需一个简单的 spawn 即可使其异步。

标签: python python-asyncio


【解决方案1】:

尽管从表面上看 asyncio 一个孤注一掷的交易,但在处理遗留或异构环境时仍有两个逃生口可以提供帮助:

  • 在 asyncio 中,您可以 await loop.run_in_executor(callable, args...) 在另一个线程中评估同步代码,暂停当前协程直到结果准备好。

  • 在 asyncio 之外,您可以使用 asyncio.run_coroutine_threadsafe() 将协程提交到在另一个线程中运行的事件循环。它立即返回返回一个concurrent.futures future,它有一个阻塞result() 方法,可以阻塞当前线程而不会对事件循环产生不利影响。 (使用run_coroutine_threadsafe需要事先在专用线程中启动事件循环。)

有了这两个工具供您使用,混合 asyncio 和经典同步代码并不难。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-09-14
    • 1970-01-01
    • 2021-05-04
    • 2019-07-13
    • 2018-08-12
    • 2019-05-14
    • 1970-01-01
    相关资源
    最近更新 更多