如果我作为 worker 运行一个具有以下函数的线程,
q = queue.Queue()
def worker():
while True:
t = {}
for i in range(3):
t['a'] = i
q.put(t)
队列中填充了完全相同的字典,即 {'a': 2}
而不是序列 {'a': 0}, {'a' : 1}, {'a': 2}
。我认为这是因为 put()
方法在 for 循环完成并且 i
的最后一个值为 2 之后运行。我的解释对吗?
现在,如果我将字典的实例化移动到 for 循环中,
def worker():
while True:
for i in range(3):
t = {'a': i}
q.put(t)
队列中填充了所需的序列。我的解释是,首先,我在内存中创建一个字典对象,然后开始一个 for 循环并重新分配它的值 3 次,但是 put()
调用发生在循环完成之后。在第二个实例中,我在 for 循环的每次迭代中创建一个新的字典对象,因此当 put()
调用发生在循环之后时,它们使用自己的键访问字典的 3 个不同实例 -值对。
谁能阐明幕后发生的事情?
我的解释对吗?
您观察到这种行为是因为您一直在修改同一个对象
让我们抛开队列/线程并运行一个简化的等效代码,其中包含一些打印
以了解正在发生的事情
t = {}
l = []
for i in range(3):
t['a'] = i
l.append(t)
print(l)
t['a'] = 20
print(l)
print(map(id, l))
[{'a': 2}, {'a': 2}, {'a': 2}]
[{'a': 20}, {'a': 20}, {'a': 20}]
# they are all the same!
[4474861840, 4474861840, 4474861840]
所以它与我们的线程/队列无关——你只是将同一个对象添加了 3 次。
现在,如果我将字典的实例化移动到 for 循环中
在这种情况下,您每次都创建一个新对象,如以下代码所示:
l = []
for i in range(3):
t = {}
t['a'] = i
l.append(t)
print(l)
t['a'] = 20
print(l)
print(map(id, l))
[{'a': 0}, {'a': 1}, {'a': 2}]
[{'a': 0}, {'a': 1}, {'a': 20}]
# they are all different!
[4533475600, 4533502592, 4533502872]
所以这里没有魔法
回到你的问题
您可能会感兴趣:“Python 的 queue.Queue.put() 线程安全吗?”意味着可以访问全局变量 q由多个并发线程安全地进行。
答案是yes - 它是线程安全的
The Queue module implements multi-producer, multi-consumer queues. It
is especially useful in threaded programming when information must be
exchanged safely between multiple threads. The Queue class in this
module implements all the required locking semantics