<p>为了便于讨论,这里有一个简单的生成器函数来提供一些数据:</p>
<pre><code>from random import randint
def generator1():
for i in range(10000):
yield (randint(1,10), randint(1,100))
</code></pre>
<p>下面是一个基本的解决方案,它使用Python for循环来使用生成器并统计每个键值对的计数</p>
<pre><code>from collections import defaultdict
tally = defaultdict(int)
for k,v in generator1():
tally[k] += v
for k in sorted(tally):
print k, tally[k]
</code></pre>
<p>将打印如下内容:</p>
<pre><code>1 49030
2 51963
3 51396
4 49292
5 51908
6 49481
7 49645
8 49149
9 48523
10 50722
</code></pre>
<p>但我们可以创建一个协程,它将接受发送给它的每个键值对,并将它们全部累加到传递给它的defaultdict中:</p>
<pre><code># define coroutine to update defaultdict for every
# key,value pair sent to it
def tallyAccumulator(t):
try:
while True:
k,v = (yield)
t[k] += v
except GeneratorExit:
pass
</code></pre>
<p>我们将使用tally defaultdict初始化协程,并通过向它发送一个None值来准备接受值:</p>
<pre><code># init coroutine
tally = defaultdict(int)
c = tallyAccumulator(tally)
c.send(None)
</code></pre>
<p>我们可以使用for循环或列表理解将所有生成器值发送到协同程序:</p>
<pre><code>for val in generator1():
c.send(val)
</code></pre>
<p>或者</p>
<pre><code>[c.send(val) for val in generator1()]
</code></pre>
<p>但是,我们将使用大小为零的deque来处理生成器表达式的所有值,而不创建不必要的None临时列表:</p>
<pre><code># create generator expression consumer
from collections import deque
do_all = deque(maxlen=0).extend
# loop thru generator at C speed, instead of Python for-loop speed
do_all(c.send(val) for val in generator1())
</code></pre>
<p>现在我们再来看看这些价值观:</p>
<pre><code>for k in sorted(tally):
print k, tally[k]
</code></pre>
<p>我们得到了另一个与第一个类似的列表:</p>
<pre><code>1 52236
2 49139
3 51848
4 51194
5 51275
6 50012
7 51875
8 46013
9 50955
10 52192
</code></pre>
<p>在David Beazley的页面上阅读更多关于协作的信息:<a href="http://www.dabeaz.com/coroutines/">http://www.dabeaz.com/coroutines/</a></p>