Python: передать словарь в другой поток, используя очередь - PullRequest
1 голос
/ 08 ноября 2019

Я передаю словарь в другой поток, используя очередь. Я ожидал получить два разных словаря, но на самом деле я получил один и тот же словарь дважды. Я могу сделать глубокую копию, чтобы исправить проблему, но есть ли лучший способ вместо глубокой копии каждый раз?

import threading 
from queue import Queue
import time
import copy
q = Queue()

def put(q): 
    d = {}
    d[1] = 2
    print(' send d = {}'.format(d))
    q.put(d)
    # d = copy.deepcopy(d) # uncomment this line to fix the problem
    d.pop(1)
    print(' send again d = {}'.format(d))
    q.put(d)

def get(q): 
    d = q.get()
    print(' received d = {}'.format(d))
    d = q.get()
    print(' received again d = {}'.format(d))

if __name__ == "__main__": 
    t1 = threading.Thread(target=put, args=(q,)) 
    t2 = threading.Thread(target=get, args=(q,)) 
    t1.start() 
    t2.start() 
    t1.join() 
    t2.join() 
    print("Done!") 

Ответы [ 3 ]

0 голосов
/ 08 ноября 2019

Нет проблем с вашим кодом. Это на самом деле правильное поведение. До того как поток получателя получил первое сообщение, вы фактически изменили словарь. Вот почему вы дважды получаете пустой словарь в ветке получателя. Я просто смоделировал задержку (2 секунды) перед изменением словаря. Теперь вы можете видеть поток получателя, получающий оба состояния.

import threading
from queue import Queue
import time
import copy
q = Queue()

def put(q):
    d = {}
    d[1] = 2
    print('send d = {}'.format(d))
    q.put(d)
    # d = copy.deepcopy(d) # uncomment this line to fix the problem
    #Add a 2 sec delay to allow other thread to receive.
    time.sleep(2)
    d.pop(1)
    print(' send again d = {}'.format(d))
    q.put(d)

def get(q):
    d = q.get()
    print(' received d = {}'.format(d))
    d = q.get()
    print(' received again d = {}'.format(d))

if __name__ == "__main__":
    t1 = threading.Thread(target=put, args=(q,))
    t2 = threading.Thread(target=get, args=(q,))
    t1.start()
    t2.start()
    t1.join()
    t2.join()
    print("Done!")

здесь вывод

отправить d = {1: 2}
получено d = {1: 2}
отправить еще раз d = {}
Получено снова d = {}
Готово!

в контексте обмена сообщениями, 2 сообщения обычно ссылаются на 2 различных объекта, которые вы можете достичь с помощью deepcopy or dict(d) .

Надеюсь, это поможет.

0 голосов
/ 08 ноября 2019

Добавьте потоковое событие, оно будет продолжено сразу же после завершения вашей работы: установите exit_thread.set () после первой печати. Ваш второй звонок не произойдет, пока не закончится первый звонок. Он заканчивается немедленно, без фактического времени ожидания, за исключением ожидания завершения первого вызова, поэтому продолжается мгновенно. Это самый быстрый способ выполнить то, что вы делаете. Надеюсь, это поможет!

import threading 
from queue import Queue
import time
import copy
q = Queue()


exit_thread = threading.Event()

def background_thread():
    while True:
        if exit_thread.wait(timeout=10):
            break

def put(q): 
    d = {}
    d[1] = 2
    print(' send d = {}'.format(d))
    q.put(d)
    # This waits until until q.put(d) is finished. You just need to tell it when to break by
    # using exit_thread.set()
    background_thread()
    # d = copy.deepcopy(d) # uncomment this line to fix the problem
    d.pop(1)
    print(' send again d = {}'.format(d))
    q.put(d)

def get(q): 
    d = q.get()
    # This breaks the timeout function, so no wait time in your case
    exit_thread.set()
    print(' received d = {}'.format(d))
    d = q.get()
    print(' received again d = {}'.format(d))

if __name__ == "__main__": 
    t1 = threading.Thread(target=put, args=(q,)) 
    t2 = threading.Thread(target=get, args=(q,)) 
    t1.start() 
    t2.start() 
    t1.join() 
    t2.join() 
    print("Done!") 
0 голосов
/ 08 ноября 2019

Проблема в том, что вы изменяете тот же словарь, который вы помещаете в очередь. Простое решение здесь состоит в том, чтобы непосредственно создать новый. Вот модифицированный код ...

import threading
from queue import Queue
q = Queue()

def put(q): 
    d = {1:2}
    print(' send d = {}'.format(d))
    q.put(d)
    d = {3:4}
    print(' send again d = {}'.format(d))
    q.put(d)

def get(q):
    d = q.get()
    print(' received d = {}'.format(d))
    d = q.get()
    print(' received again d = {}'.format(d))

if __name__ == "__main__":
    t1 = threading.Thread(target=put, args=(q,))
    t2 = threading.Thread(target=get, args=(q,)) 
    t1.start() 
    t2.start() 
    t1.join() 
    t2.join() 
    print("Done!")

Технически в вашем исходном коде есть условие гонки. pop выполняется до того, как ваша очередь сможет отправить его и распечатать другим потоком.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...