目录


基本概念[TOC]

生成器函数是包含yield语句的函数。在生成器函数中,不能包含带参的return语句。
调用生成器函数,会返回一个生成器对象。
第一次启动生成器的时候,需要使用None作为参数调用生成器的send()方法,或者调用生成器的next()方法(next()等价于send(None))。生成器会从头开始执行,一直到:

之后,可以使用send(<value>)或next()重新启动生成器,send的参数会作为上个yield语句的返回值,然后生成器会从上次yield的位置,继续执行,一直到:

也可以通过生成器对象的throw(<exc_value>)方法,向生成器内部传递异常。


例子[TOC]

下面是一个用生成器,模拟生产者-消费者的例子:

[root@iZj6chejzrsqpclb7miryaZ ~]# cat test.py 
import time

class MainLoop:
    def __init__(self):
        self._gens = []
        self._is_stop = False

    def add_gen(self, gen_factory):
        if self._is_stop:
            return
        self._gens.append(gen_factory(self))

    def delete_gen(self, gen):
        while self._gens.find(gen) != -1:
            self._gens.remove(gen)

    def _run(self):
        cursor = 0
        while cursor < len(self._gens):
            try:
                self._gens[cursor].next()
            except Exception as ex:
                self._gens.pop(cursor)
                cursor = cursor - 1
                if not isinstance(ex, StopIteration):
                    print ex
            finally:
                cursor = cursor + 1

    def start(self):
        while not self._is_stop:
            self._run()
            if not self._gens:
                time.sleep(0.001)
        while self._gens:
            self._run()

    def stop(self):
        self._is_stop = True

current_count = 0
will_stop = False
batch_count = 10
max_count = 100


def producer(loop):
    global current_count, max_count, batch_count, will_stop
    produced_count = 0

    while produced_count < max_count:
        while current_count >= max_count / 2:
            print "[producer] threshold is reached..."
            yield

        print "[producer] begin producing"
        start_time = time.time()
        now = start_time
        while now - start_time < 0.2:
            yield
            now = time.time()

        current_count = current_count + batch_count
        produced_count = produced_count + batch_count
        print "[producer] produced %d/%d" % (produced_count, max_count)
        yield
    print "[producer] stop"
    will_stop = True
    loop.stop()

def consumer(loop):
    global current_count, will_stop
    consumed_count = 0

    while current_count > 0 or not will_stop:
        while current_count <= 0:
            print "[consumer] no goods, sleep 0.1"

            start_time = time.time()
            now = start_time
            while now - start_time < 1:
                yield
                now = time.time()

        current_count = current_count - 1
        consumed_count = consumed_count + 1
        print "[consumer] consumed %d/%d" % (consumed_count, max_count)
        yield
    print "[consumer] stop"

loop = MainLoop()
loop.add_gen(producer)
loop.add_gen(consumer)
loop.start()

[root@iZj6chejzrsqpclb7miryaZ ~]# python test.py 
[producer] begin producing
[consumer] no goods, sleep 0.1
[producer] produced 10/100
[producer] begin producing
[producer] produced 20/100
[producer] begin producing
[producer] produced 30/100
[producer] begin producing
[producer] produced 40/100
[producer] begin producing
[consumer] consumed 1/100
[consumer] consumed 2/100
[consumer] consumed 3/100
[consumer] consumed 4/100
[consumer] consumed 5/100
[consumer] consumed 6/100
[consumer] consumed 7/100
[consumer] consumed 8/100
[consumer] consumed 9/100
[consumer] consumed 10/100
[consumer] consumed 11/100
[producer] produced 50/100
[consumer] consumed 12/100
[producer] begin producing
[consumer] consumed 13/100
[consumer] consumed 14/100
[consumer] consumed 15/100
[consumer] consumed 16/100
[consumer] consumed 17/100
[consumer] consumed 18/100
[consumer] consumed 19/100
[consumer] consumed 20/100
[consumer] consumed 21/100
[consumer] consumed 22/100
[consumer] consumed 23/100
[consumer] consumed 24/100
[consumer] consumed 25/100
[consumer] consumed 26/100
[consumer] consumed 27/100
[consumer] consumed 28/100
[consumer] consumed 29/100
[consumer] consumed 30/100
[consumer] consumed 31/100
[consumer] consumed 32/100
[consumer] consumed 33/100
[consumer] consumed 34/100
[consumer] consumed 35/100
[consumer] consumed 36/100
[consumer] consumed 37/100
[consumer] consumed 38/100
[consumer] consumed 39/100
[consumer] consumed 40/100
[consumer] consumed 41/100
[consumer] consumed 42/100
[consumer] consumed 43/100
[consumer] consumed 44/100
[consumer] consumed 45/100
[consumer] consumed 46/100
[consumer] consumed 47/100
[consumer] consumed 48/100
[consumer] consumed 49/100
[consumer] consumed 50/100
[consumer] no goods, sleep 0.1
[producer] produced 60/100
[producer] begin producing
[producer] produced 70/100
[producer] begin producing
[producer] produced 80/100
[producer] begin producing
[producer] produced 90/100
[producer] begin producing
[producer] produced 100/100
[producer] stop
[consumer] consumed 51/100
[consumer] consumed 52/100
[consumer] consumed 53/100
[consumer] consumed 54/100
[consumer] consumed 55/100
[consumer] consumed 56/100
[consumer] consumed 57/100
[consumer] consumed 58/100
[consumer] consumed 59/100
[consumer] consumed 60/100
[consumer] consumed 61/100
[consumer] consumed 62/100
[consumer] consumed 63/100
[consumer] consumed 64/100
[consumer] consumed 65/100
[consumer] consumed 66/100
[consumer] consumed 67/100
[consumer] consumed 68/100
[consumer] consumed 69/100
[consumer] consumed 70/100
[consumer] consumed 71/100
[consumer] consumed 72/100
[consumer] consumed 73/100
[consumer] consumed 74/100
[consumer] consumed 75/100
[consumer] consumed 76/100
[consumer] consumed 77/100
[consumer] consumed 78/100
[consumer] consumed 79/100
[consumer] consumed 80/100
[consumer] consumed 81/100
[consumer] consumed 82/100
[consumer] consumed 83/100
[consumer] consumed 84/100
[consumer] consumed 85/100
[consumer] consumed 86/100
[consumer] consumed 87/100
[consumer] consumed 88/100
[consumer] consumed 89/100
[consumer] consumed 90/100
[consumer] consumed 91/100
[consumer] consumed 92/100
[consumer] consumed 93/100
[consumer] consumed 94/100
[consumer] consumed 95/100
[consumer] consumed 96/100
[consumer] consumed 97/100
[consumer] consumed 98/100
[consumer] consumed 99/100
[consumer] consumed 100/100
[consumer] stop