【问题标题】:Python - Await Coroutine optionally without raising RuntimeWarningPython - 可选地等待协程而不引发 RuntimeWarning
【发布时间】:2020-09-24 00:35:19
【问题描述】:

我目前有一个类似 Cache 的对象,它有一个 aget 方法,它接收要返回的对象的名称,如果键不存在则回调协程。

import asyncio

class Cache:
    def __init__(self):
        self.cache = {}

    async def aget(self, name, default):
        try:
            return self.cache["name"]
        except KeyError:
            return await default

async def foo():
    pass

async def bar(cache):
    obj = await cache.aget("duh", foo())
    # If "duh" doesn't exist, then await foo() and return it

cache = Cache()

asyncio.run(bar(cache))

所以假设密钥确实存在,那么foo() 将永远不会被等待,从而引发RuntimeWarning 抱怨协程没有被安排。

问题: 是否有一种clean 方法可以选择性地等待协程,而无需像 @987654325 那样解压协程及其参数@。我不考虑将 RuntimeWarning 作为一个选项,因为它存在于它的用例中。

【问题讨论】:

    标签: python python-asyncio


    【解决方案1】:

    问题:有没有一种干净的方法可以选择性地等待协程,而无需解压协程及其参数,如 aget("duh", foo, arg)

    您可以创建任务,但在它有机会开始运行之前将其取消:

        async def aget(self, name, default):
            try:
                obj = self.cache["name"]
            except KeyError:
                return await default
            else:
                asyncio.create_task(default).cancel()
                return obj
    

    如果您走这条路,请务必衡量创建和取消任务的开销。由于它发生在代码的(可能)热路径上,因此可能会影响您的性能。

    【讨论】:

      【解决方案2】:

      我找到了另一个答案,创建任务并取消它们可能会导致取消问题和不必要的开销。

          async def aget(self, name, default):
              try:
                  obj = self.cache["name"]
              except KeyError:
                  return await default
              else:
                  default.close()
                  return obj
      

      由于某种原因,close() 方法没有在任何地方记录,这是gc 在协程对象上调用的方法。

      编辑:正如评论所说,它记录在https://docs.python.org/3/reference/datamodel.html#coroutine-objects

      【讨论】:

      猜你喜欢
      • 2020-10-10
      • 2018-10-26
      • 2021-02-23
      • 2021-10-22
      • 2019-12-15
      • 2021-10-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多