Python生成器如何知道谁在调用?

时间:2013-05-05 20:57:03

标签: python generator

这个问题让我脱掉了头发。

如果我这样做:

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

并从一千个线程中调用它,生成器如何知道每个线程接下来要发送什么? 每当我调用它时,生成器是否会使用计数器和调用者引用或类似的东西保存一个表?

这很奇怪。

请澄清我的想法。

3 个答案:

答案 0 :(得分:6)

mygen不需要记住任何事情。每次调用mygen()都会返回一个独立的迭代。另一方面,这些迭代具有状态:每次调用next()时,它会跳转到生成器代码中的正确位置 - 当遇到yield时,控制权将被传回呼叫者,召集者。实际的实现相当混乱,但原则上你可以想象这样的迭代器存储局部变量,字节码和字节码中的当前位置(a.k.a.指令指针)。这里的线程没什么特别的。

答案 1 :(得分:2)

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

如果两个线程通过调用线程中的mygen()创建生成器,则它们将具有单独的生成器对象。

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

如果你是从C背景来看这个,那么与具有static变量的函数相同。状态保存在对象中,而不是静态地保存在函数中包含的变量中。

答案 2 :(得分: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:
    . . .

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