Является ли метод python queue.Queue.put() асинхронным?

Если я запускаю поток со следующей функцией в качестве рабочего,

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 ответа

Решение

Я правильно понимаю?

Вы наблюдаете такое поведение, потому что вы все время модифицируете один и тот же объект

Давайте отложим очереди / потоки и запустим упрощенный эквивалент вашего кода с некоторыми 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 может быть безопасно доступна нескольким параллельным потокам. Ответ - да, это потокобезопасный

Модуль Queue реализует многопользовательские, многопользовательские очереди. Это особенно полезно в многопоточном программировании, когда необходимо безопасно обмениваться информацией между несколькими потоками. Класс Queue в этом модуле реализует всю необходимую семантику блокировки

В первом примере вы помещаете один и тот же дикт в очередь три раза. Это не имеет ничего общего с очередью. Вы найдете то же поведение с list.append.

Другие вопросы по тегам