异步python itertools链多个生成器

时间:2018-11-22 01:55:01

标签: python python-3.x asynchronous python-asyncio sequence-generators

更新的清晰度:

假设我有2个处理生成器函数:

def gen1(): # just for examples,
  yield 1   # yields actually carry 
  yield 2   # different computation weight 
  yield 3   # in my case

def gen2():
  yield 4
  yield 5
  yield 6

我可以用itertools链接它们

from itertools import chain

mix = chain(gen1(), gen2())

然后我可以用它创建另一个生成器函数对象,

def mix_yield():
   for item in mix:
      yield item

或者只是如果我只想next(mix),它就在那里。

我的问题是,我该如何做异步代码中的等效项目?

因为我需要它:

  • 收益率(一对一),或使用next迭代器
  • 最快的解决方案优先(异步)

PREV。更新:

经过实验和研究,我发现aiostream库声明为itertools的异步版本,所以我做了什么:

import asyncio
from aiostream import stream

async def gen1(): 
     await asyncio.sleep(0) 
     yield 1 
     await asyncio.sleep(0) 
     yield 2 
     await asyncio.sleep(0) 
     yield 3 

async def gen2(): 
     await asyncio.sleep(0) 
     yield 4 
     await asyncio.sleep(0) 
     yield 5 
     await asyncio.sleep(0) 
     yield 6 

a_mix = stream.combine.merge(gen1(),gen2())

async def a_mix_yield():
   for item in a_mix:
      yield item

但是我仍然不能next(a_mix)

TypeError: 'merge' object is not an iterator

next(await a_mix)

raise StreamEmpty()

尽管我仍然可以将其列入列表:

print(await stream.list(a_mix))
# [1, 2, 4, 3, 5, 6]

一个目标就完成了,还有一个目标要走:

  • 收益率(一对一),或使用next迭代器

    -最快解决的收益率最高(异步)

2 个答案:

答案 0 :(得分:3)

next的异步等效项是异步迭代器上的__anext__方法。反过来,通过对可迭代对象调用__aiter__(类似于__iter__)来获得迭代器。展开的异步迭代如下所示:

a_iterator = obj.__aiter__()          # regular method
elem1 = await a_iterator.__anext__()  # async method
elem2 = await a_iterator.__anext__()  # async method
...

当没有更多元素可用时,__anext__方法将引发StopAsyncIteration。要遍历异步迭代器,应使用async for而不是for

这是一个基于您的代码的可运行示例,同时使用__anext__async for耗尽用aiostream.stream.combine.merge设置的流:

async def main():
    a_mix = stream.combine.merge(gen1(), gen2())
    async with a_mix.stream() as streamer:
        mix_iter = streamer.__aiter__()    
        print(await mix_iter.__anext__())
        print(await mix_iter.__anext__())
        print('remaining:')
        async for x in mix_iter:
            print(x)

asyncio.get_event_loop().run_until_complete(main())

答案 1 :(得分:1)

我遇到了这个答案,然后看了看aiostream库。这是我想出的用于合并多个异步生成器的代码。它不使用任何库。

async def merge_generators(gens:Set[AsyncGenerator[Any, None]]) -> AsyncGenerator[Any, None]:
    pending = gens.copy()
    pending_tasks = { asyncio.ensure_future(g.__anext__()): g for g in pending }
    while len(pending_tasks) > 0:
        done, _ = await asyncio.wait(pending_tasks.keys(), return_when="FIRST_COMPLETED")
        for d in done:
            try:
                result = d.result()
                yield result
                dg = pending_tasks[d]
                pending_tasks[asyncio.ensure_future(dg.__anext__())] = dg
            except StopAsyncIteration as sai:
                print("Exception in getting result", sai)
            finally:
                del pending_tasks[d]

希望这对您有帮助,如果有任何错误,请告诉我。

相关问题