python的queue.Queue.put()方法是异步的吗?

时间:2018-02-08 07:40:41

标签: multithreading python-3.x queue late-binding

如果我使用以下函数运行一个线程作为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个不同实例。

任何人都可以了解幕后发生的事情吗?

2 个答案:

答案 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次。

现在,如果我在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 - 它是线程安全的

  

Queue模块实现多生产者,多消费者队列。它   当信息必须时,在线程编程中特别有用   在多个线程之间安全地交换这个队列类   module实现了所有必需的锁定语义