这个问题让我脱掉了头发。
如果我这样做:
def mygen():
for i in range(100):
yield i
并从一千个线程中调用它,生成器如何知道每个线程接下来要发送什么? 每当我调用它时,生成器是否会使用计数器和调用者引用或类似的东西保存一个表?
这很奇怪。
请澄清我的想法。
答案 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:
. . .
这可能会造成各种各样的破坏。 : - )