6

这个问题让我把头发拉出来。

如果我做:

def mygen():
    for i in range(100):
        yield i

并从一千个线程中调用它,生成器如何知道每个线程接下来要发送什么?

每次我调用它时,生成器是否会保存一个带有计数器和调用者引用的表或类似的东西?

有点奇怪。

请澄清我的想法。

4

3 回答 3

6

mygen不必记住任何东西。每次调用都mygen()返回一个独立的迭代。另一方面,这些可迭代对象具有状态:每次next()调用一个时,它都会跳转到生成器代码中的正确位置——当yield遇到 a 时,将控制权交还给调用者。实际实现相当混乱,但原则上您可以想象这样的迭代器存储局部变量、字节码和字节码中的当前位置(也称为指令指针)。这里的线程没有什么特别之处。

于 2013-05-05T21:01:26.380 回答
2

像这样的函数在调用时将返回一个生成器对象。如果您有单独的线程调用next()同一个生成器对象,它们将相互干扰。也就是说,5个线程next()每个调用10次会得到50个不同的yield。

如果两个线程各自通过在线程内调用来创建一个生成器mygen(),那么它们将拥有单独的生成器对象。

生成器是一个对象,它的状态将存储在内存中,因此每个创建的两个线程mygen()将引用不同的对象。这与从 a 创建对象的两个线程没有什么不同class,它们每个都有不同的对象,即使类是相同的。

如果你是从 C 背景来的,这static带有变量的函数不同。状态保存在对象中,而不是静态保存在函数中包含的变量中。

于 2013-05-05T21:00:58.423 回答
1

如果你这样看可能会更清楚。代替:

for i in mygen():
    . . .

采用:

gen_obj = mygen()
for i in gen_obj:
    . . .

然后你可以看到 mygen() 只被调用了一次,它创建了一个新对象,并且被迭代的是那个对象。如果需要,您可以在同一个线程中创建两个序列:

gen1 = mygen()
gen2 = mygen()
print(gen1.__next__(), gen2.__next__(), gen1.__next__(), gen2.__next__())

这将打印 0、0、1、1。

如果愿意,您可以从两个线程访问相同的迭代器,只需将生成器对象存储在全局中:

global_gen = mygen()

线程 1:

for i in global_gen:
    . . .

线程 2:

for i in global_gen:
    . . .

这可能会造成各种破坏。:-)

于 2013-05-05T21:32:48.050 回答