python 的 queue.Queue.put() 方法是异步的吗?
Is python's queue.Queue.put() method asynchronous?
如果我运行一个具有以下功能的线程作为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()
方法 运行s 在 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 个不同实例。
任何人都可以阐明幕后发生的事情吗?
在第一个示例中,您将同一个字典放入队列中三次。这与队列无关。您会发现 list.append 有相同的行为。
我的理解对吗?
您观察到这种行为是因为您一直在修改同一个对象
让我们抛开队列/线程和 运行 一个简化的等效代码,其中包含一些 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]
所以这与我们无关 threads/queues - 您只是将同一个对象添加了 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
如果我运行一个具有以下功能的线程作为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()
方法 运行s 在 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 个不同实例。
任何人都可以阐明幕后发生的事情吗?
在第一个示例中,您将同一个字典放入队列中三次。这与队列无关。您会发现 list.append 有相同的行为。
我的理解对吗?
您观察到这种行为是因为您一直在修改同一个对象
让我们抛开队列/线程和 运行 一个简化的等效代码,其中包含一些 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]
所以这与我们无关 threads/queues - 您只是将同一个对象添加了 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