当前位置: 首页 > 面试题库 >

创建在协程结束时产生协程结果的生成器

欧阳绪
2023-03-14
问题内容

当前,我有一个效率低下的同步生成器,该生成器按顺序发出许多HTTP请求并产生结果。我想使用请求asyncioaiohttp使其并行化,从而加快此生成器的速度,但我想将其保留为普通生成器(而不是PEP
525异步生成器
),以便不需要调用它的非异步代码被修改。如何创建这样的生成器?


问题答案:

asyncio.as_completed(),目前几乎没有文献记录,它接受一个协程或期货的迭代,并按输入期货的完成顺序返回一个迭代的期货。
通常 ,您可以awaitasync函数内部遍历其结果和成员。

import asyncio

async def first():
    await asyncio.sleep(5)
    return 'first'

async def second():
    await asyncio.sleep(1)
    return 'second'

async def third():
    await asyncio.sleep(3)
    return 'third'

async def main():
    for future in asyncio.as_completed([first(), second(), third()]):
        print(await future)

loop = asyncio.get_event_loop()

# Prints 'second', then 'third', then 'first'
loop.run_until_complete(main())

…但是出于这个问题的目的,我们想要的是能够从普通的生成器中产生这些结果,以便普通的同步代码可以在不知道async函数在内部被使用的情况下使用它们。我们可以loop.run_until_complete()通过as_completed看涨看涨期权来实现这一目标。

import asyncio

async def first():
    await asyncio.sleep(5)
    return 'first'

async def second():
    await asyncio.sleep(1)
    return 'second'

async def third():
    await asyncio.sleep(3)
    return 'third'

def ordinary_generator():
    loop = asyncio.get_event_loop()
    for future in asyncio.as_completed([first(), second(), third()]):
        yield loop.run_until_complete(future)

# Prints 'second', then 'third', then 'first'
for element in ordinary_generator():
    print(element)

这样一来,我们已经暴露了我们的异步代码,非异步土地在不需要调用者定义任何功能的方式async,或者即使知道ordinary_generator正在使用asyncio引擎盖下。

作为ordinary_generator()在某些情况下提供更大灵活性的一种替代实现,我们可以重复asyncio.wait()使用该FIRST_COMPLETED标志而不是循环进行as_completed()

import concurrent.futures

def ordinary_generator():
    loop = asyncio.get_event_loop()
    pending = [first(), second(), third()]
    while pending:
        done, pending = loop.run_until_complete(
            asyncio.wait(
                pending,
                return_when=concurrent.futures.FIRST_COMPLETED
            )
        )
        for job in done:
            yield job.result()

这种维护pending作业列表的方法的优势在于,我们可以对其进行调整,以将作业动态添加到pending列表中。这在某些情况下很有用,在这种情况下,我们的异步作业会向队列中添加无法预测的其他作业数量,例如,在其访问的每个页面上跟随所有链接的网络蜘蛛。



 类似资料:
  • 本文向大家介绍unity3d 结束协程,包括了unity3d 结束协程的使用技巧和注意事项,需要的朋友参考一下 示例 通常,您将协程设计为在达到某些目标时自然终止。 要从协程“内部”阻止协程,您不能像在普通功能中早退一样简单地“返回”。而是使用yield break。 您还可以强制脚本启动的所有协程在完成之前停止。 从调用方停止特定协程的方法因启动方式而异。 如果您通过字符串名称启动了协程: 那么

  • 问题内容: 基于生成器的协程具有一种方法,该方法允许调用方和被调用方之间进行双向通信,并从调用方恢复生成的生成协程。这是将生成器变成协程的功能。 尽管新的本机协程为异步I / O提供了出色的支持,但我看不出如何获得与之等效的协程。明确禁止使用in函数,因此本机协程只能使用一条语句返回一次。尽管表达式将新值带入协程中,但这些值来自被调用方,而不是调用方,并且等待的调用从每次开始就进行评估,而不是从中

  • 有几种不同方法可以生成查询结果: 结果数组 结果行 自定义结果对象 结果辅助方法 Class Reference 结果数组 result() 方法 该方法以**对象数组**形式返回查询结果,如果查询失败返回**空数组**。 一般情况下,你会像下面这样在一个 foreach 循环中使用它: $query = $this->db->query("YOUR QUERY"); foreach ($que

  • 问题内容: 我已经读过在CPython中,解释器堆栈(为此目的而调用的Python函数的列表)与C堆栈(在解释器自己的代码中调用的C函数的列表)混合在一起。如果是这样,那么如何实现生成器和协程?他们如何记住执行状态?CPython是否将每个生成器/协程的堆栈复制到OS堆栈或从OS堆栈复制?还是CPython只是将生成器的最高堆栈帧保留在堆上,因为生成器只能从该最高帧产生? 问题答案: 该指令将当前

  • 我正在使用OpenNLP处理诸如“在洛杉矶工作的医生”和“住在好莱坞并在圣莫尼卡工作的女性”之类的查询。对于理解人类的英语来说,这些句子很明显,主题是“医生”和“女性”。然而,当我使用opennlp时,它将句子标记为 [女性生活][好莱坞] 这是另一个句子“住在圣莫尼卡、在马里布工作和踢足球的人”被处理为 为什么OpenNLP的POS标记器错误地标记了它们?这些句子有最简单的语法结构。如果最先进的

  • 问题内容: 似乎将CMake + CTest集成到jenkins中应该很容易。该cmakebuilder插件是非常容易配置(刚才设置的源树和构建树,完成了!)。但是我不明白如何调用CTest步骤。 根据xUnit主页,自1.58版以来,支持CTest的XML输出,请参见bug报告。 那就是我能找到的所有文档。当我在google或stackoverflow上搜索时,我只能找到非常老的文档,需要手动操