如果我使用以下函数运行一个线程作为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个不同实例。
任何人都可以了解幕后发生的事情吗?
答案 0 :(得分:2)
在第一个示例中,您将相同的dict放入队列三次。这与队列无关。你会发现list.append的行为相同。
答案 1 :(得分:2)
您会观察到这种行为,因为您一直在修改同一个对象
让我们把队列/线程放在一边,用一些prints
运行代码的简化等价物,以了解正在发生的事情
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次。
在这种情况下,您每次都会创建一个新对象,如下面的代码所示:
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 - 它是线程安全的
Queue模块实现多生产者,多消费者队列。它 当信息必须时,在线程编程中特别有用 在多个线程之间安全地交换这个队列类 module实现了所有必需的锁定语义