У меня есть 1 очередь, к которой обращаются 2 многопроцессорные функции. Оба эти процесса потребляют один и тот же элемент в очереди, а затем очищают его. Я хочу, чтобы каждый из них имел только одно уникальное значение. Что я делаю неправильно?

import time
import queue
import multiprocessing
import threading

q = queue.Queue(maxsize=0)
run_1 = 1
run_2 = 1

def multi_one():
    while run_1 == 1:
        item = q.get()
        q.task_done()
        time.sleep(2)
        print(item)

def multi_two():
    while run_2 == 1:
        item = q.get()
        q.task_done()
        time.sleep(2)
        print(item)

p1 = multiprocessing.Process(target=multi_one)
p2 = multiprocessing.Process(target=multi_two)

for item in range(10):
    q.put(item)

p1.start()
p2.start()

Вывод, который я получаю:

0
0
1
1
2
2
...

Результат, который я ищу:

0
1
2
3
4
5
6
7
8
9
1
Neel 29 Авг 2020 в 18:36

2 ответа

Лучший ответ

Ваш код содержит несколько ошибок, описание которых я процитирую из документации:

  • Вы должны защитить "точку входа" программы, используя if __name__ == '__main__'

Убедитесь, что основной модуль может быть безопасно импортирован новым интерпретатором Python, не вызывая непреднамеренных побочных эффектов (таких как запуск нового процесса).

  • Вы должны передать объект очереди в качестве аргумента конструктору.

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

  • Вы должны использовать multiprocessing.Queue или multiprocessing.JoinableQueue, если хотите использовать JoinableQueue.task_done() Поскольку queue.Queue используется только в многопоточном контексте, когда и производитель, и потребитель находятся в одном процессе.

Учитывая приведенные выше примечания, ваш код можно изменить таким образом (хотя он все еще далек от идеала):

import time
import multiprocessing

import threading

q = multiprocessing.JoinableQueue(maxsize=0)
run_1 = 1
run_2 = 1

def multi_one(q):
    while run_1 == 1:
        item = q.get()
        q.task_done()
        time.sleep(2)
        print(item)

def multi_two(q):
    while run_2 == 1:
        item = q.get()
        q.task_done()
        time.sleep(2)
        print(item)

if __name__ == "__main__":
    p1 = multiprocessing.Process(target=multi_one, args=(q, ))
    p2 = multiprocessing.Process(target=multi_two, args=(q, ))

    for item in range(10):
        q.put(item)

    p1.start()
    p2.start()

Выход:

0
1
2
3
...
2
Alex Noname 29 Авг 2020 в 16:27

Вы используете неправильный тип Queue, попробуйте изменить его на multiprocessing.JoinableQueue:

import time
import multiprocessing

q = multiprocessing.JoinableQueue(maxsize=0)
run_1 = 1
run_2 = 1

def multi_one(q):
    while run_1 == 1:
        item = q.get()
        q.task_done()
        time.sleep(2)
        print(item)

def multi_two(q):
    while run_2 == 1:
        item = q.get()
        q.task_done()
        time.sleep(2)
        print(item)

for item in range(10):
    q.put(item)

p1 = multiprocessing.Process(target=multi_one, args=(q, ))
p2 = multiprocessing.Process(target=multi_two, args=(q, ))

p1.start()
p2.start()

Печать :

0
1
2
3
4
5
6
7
8
9
1
Andrej Kesely 29 Авг 2020 в 16:14