如何将多个阻塞Python生成器复用到一个?

时间:2012-02-08 01:43:24

标签: python generator python-2.7

考虑以下伪代码:

def g_user():
    while True:
        yield read_user_input()

def g_socket():
    while True:
        yield read_socket_input()

def g_combined(gu, gs):
    # should read user or socket input, whichever is available

    while True:
        sel = select(gu, gs)
        if sel.contains(gu):
            yield gu.next()
        if sel.contains(gs):
            yield gs.next()

gc = g_combined ( g_user(), g_socket() )

如何以最简单的方式实现这一目标?

3 个答案:

答案 0 :(得分:8)

看起来就像有人已经实现了这个:http://www.dabeaz.com/generators/genmulti.py

在这里反映:

import Queue, threading
def gen_multiplex(genlist):
    item_q = Queue.Queue()
    def run_one(source):
        for item in source: item_q.put(item)

    def run_all():
        thrlist = []
        for source in genlist:
            t = threading.Thread(target=run_one,args=(source,))
            t.start()
            thrlist.append(t)
        for t in thrlist: t.join()
        item_q.put(StopIteration)

    threading.Thread(target=run_all).start()
    while True:
        item = item_q.get()
        if item is StopIteration: return
        yield item

答案 1 :(得分:1)

为了使select.select()正常工作,您需要在生成器上公开一个返回基础文件描述符的fileno()方法。

答案 2 :(得分:-2)

标准库中的itertools模块包含很好的函数。在这种特殊情况下,循环功能很好。

循环帮助说:

  

循环(可迭代) - >循环对象

     

从迭代中返回元素,直到它耗尽为止。然后   无限期地重复序列。

在解决方案中使用循环:

import itertools

def g_user():
    while True:
        yield read_user_input()

def g_socket():
    while True:
        yield read_socket_input()


def g_combine(*generators):
    for generator in itertools.cycle(generators):
        yield generator.next()


g_combined =  g_combine(g_user(), g_socket())

关于此代码的注意事项:

  1. g_combine以第一个引发StopIteration

  2. 的生成器结束
  3. g_combine接受N个生成器

  4. 如何正确捕获异常?想一想。