如何统一基于发送者和接收者的协同程序?

时间:2013-11-25 10:35:27

标签: python coroutine

据我所知,Python中的协程概念,你基本上可以有两种不同的传递数据模式(抱歉,我无法找到或找到更好的术语):

  1. 基于发件人的:每个协程都会从“外部”消费数据并将其发送给消费者,例如

    def coro(consumer):
        while True:
            item = yield
            consumer.send(process(item))
    

    要构建管道,可以从外部协程到内部生成:

    producer(filter(sink()))
    
  2. 基于Receiver的:每个协同程序都会从​​其参数和产量中消耗数据 它给消费者,例如

    def coro(producer):
        while True:
            item = next(producer)
            yield process(item)
    

    要构建管道,可以从内部到外部协程生成, 这最终看起来更像人们对功能的期望:

    sink(filter(producer()))
    
  3. 这两种方法都有其自身的优势。使用基于发送者的协同程序,我可以 广播给许多消费者

        def broadcast(consumers):
            while True:
                item = yield
                for consumer in consumers:
                    consumer.send(item)
    

    但是,基于发送方的协程始终仅限于一个“输入”协程 因为他们无法分辨谁送他们什么(嗯,实际上是的,但那 会很讨厌)。另一方面,这基于接收器是微不足道的 协程:

        def adder(producer1, producer2):
            while True:
                x = next(producer1)
                y = next(producer2)
                yield x + y
    

    现在我的问题是:是否有任何理智和简单的方法来统一这两种方法?例如,广播加法器的结果?

1 个答案:

答案 0 :(得分:0)

我的猜测是,只能这样做:

def adder(producer1, producer2, consumers):
    while True:
        x = next(producer1)
        y = next(producer2)
        for consumer in consumers:
            consumer.send(x+y)

然后只需致电adder(x_producer, y_producer, consumers)。如图所示:enter image description here

加法器不能放在管道中间,原因是它必须包含对消费者和生产者的所有引用,如果我们在下面调用加法器,这是可能的。最高级别。

更新:这是另一种让加法器成为生成器的方法:

class AdderWithBroadcast(object):

    consumers = []

    def __init__(self, x_prod, y_prod):
        self.x_prod = x_prod
        self.y_prod = y_prod

    def __iter__(self):
        return self

    def next(self):
        x = next(self.x_prod)
        y = next(self.y_prod)

        for consumer in self.consumers:
            consumer.send(x+y)

        return x+y

    def consumer():
        while True:
            a = (yield)
            print a, ' in consumer'


k = iter(range(10))
adder = AdderWithBroadcast(k, k)
cons = consumer()
cons.send(None)
adder.consumers.append(cons)
for i in adder: 
    #  I won't include the actual result here, you can try in no your own
    print i

装饰员方法

class Broadcaster(object):

    consumers = []

    def __init__(self, gen):
        self.gen = gen

    def __iter__(self):
        return self

    def __call__(self, *args, **kwargs):
        self.gen = self.gen(*args, **kwargs)

    def next(self):
        yielded = next(self.gen)

        for consumer in self.consumers:
            consumer.send(yielded)

        return yielded


@Broadcaster
def adder(producer1, producer2):
        while True:
            x = next(producer1)
            y = next(producer2)
            yield x + y
#  result is the same as in previous solution