关于多线程:python的queue.Queue.put()方法是异步的吗?

Is python's queue.Queue.put() method asynchronous?

本问题已经有最佳答案,请猛点这里访问。

如果我作为工作线程运行具有以下函数的线程,

1
2
3
4
5
6
7
8
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循环中移动字典的实例化,

1
2
3
4
5
def worker():
    while True:
        for i in range(3):
            t = {'a': i}
            q.put(t)

号

队列中填充了所需的序列。我的解释是,在第一个实例中,我在内存中创建一个dictionary对象,然后开始一个for循环,并重新分配它的值3次,但是put()调用在循环完成后发生。在第二个实例中,我在for循环的每次迭代中都创建一个新的dictionary对象,因此当put()调用在循环之后发生时,它们使用自己的键值对访问字典的3个不同实例。

有人能告诉我窗帘后面发生了什么吗?


我解释得对吗?

你观察这种行为是因为你一直在修改同一个对象

让我们把队列/线程放在一边,用一些prints运行一个简化的代码等价物来了解正在发生的事情。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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循环中移动字典的实例化

在这种情况下,每次都创建一个新的对象,如下面的代码中所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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。答案是肯定的-它是线程安全的

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

号


在第一个示例中,您将把同一个dict放入队列三次。这与队列无关。您会发现list.append有相同的行为。