Программа, работающая с многопоточностью, зависает при использовании многопроцессорной обработки

#opencv #python-multiprocessing #python-multithreading

#opencv #python-многопроцессорная обработка #python-многопоточность

Вопрос:

Я практикуюсь с многопоточностью и многопроцессорностью, и я попытался реализовать одну и ту же программу, используя оба подхода.
Идея состоит в том, чтобы иметь два параллельных потока / процесса: один считывает кадры с веб-камеры и отправляет их в очередь, другие извлекают их и отображают.

 import json
import queue, threading
from queue import Queue
import trigger_events
import multiprocessing as mp
import cv2


class system_manager():
    def __init__(self, source):

        ## camera reader
        self.camera_queue = queue.Queue(maxsize=1)
        # self.cam_read = threading.Thread(target=Camera_Reader, args=(source, self.camera_queue))
        self.cam_read = mp.Process(target=Camera_Reader, args=(source, self.camera_queue))
        self.cam_read.daemon = True
        self.cam_read.start()

        ## module for managing triggers (user/mug position)
        # self.cam_display = threading.Thread(target=Camera_Display, args=(self.camera_queue,))
        self.cam_display = mp.Process(target=Camera_Display, args=(self.camera_queue,))
        self.cam_display.daemon = True
        self.cam_display.start()



def Camera_Reader(source, camera_queue):
    print("Cam Loading...")
    cap=cv2.VideoCapture(source)
    print("Cam Loaded...")
    while(True):
        # print(f"frame: {counter}")
        ret, frame = cap.read()
        # counter  = 1
        camera_queue.put(frame)


def Camera_Display(camera_queue):
    counter_frame = 0
    while(True):
        try:
            print(f"nFrame: {counter_frame}")
            frame = camera_queue.get()
            key = cv2.waitKey(1)
            if (key == ord('q')):
                break
            print("Here")
            counter_frame  = 1
            cv2.imshow("Frame", frame)
        except camera_queue.Empty:
            print("Nothing in queue!!!")
    cv2.destroyAllWindows()



if __name__ == "__main__":
    SM = system_manager(source=0)

  

Странно то, что если я использую потоки для двух отдельных задач, все работает нормально.
С другой стороны, если я назначаю их разным процессам, зависает тот, который должен показывать кадры (Camera_Display)…Я получаю вывод:

 Frame: 0
Cam Loaded...
  

итак, строка print(«Здесь») не выполняется, и процесс зависает во время первой итерации цикла while.
Я предполагаю, что оба подхода должны использоваться для решения этой проблемы, я не понимаю, что происходит не так, когда я использую многопроцессорную обработку.

Ответ №1:

Недостаточно заменить потоки процессами, вы также должны использовать multiprocessing.Queue вместо queue.Queue . Последняя предназначена для потоков по умолчанию.

https://docs.python.org/3/library/multiprocessing.html#exchanging-objects-between-processes

Комментарии:

1. Это не было причиной моей проблемы, я решил ее с помощью set_start_method(«spawn»). Однако, когда процессы, наконец, начали выполняться, мне пришлось использовать mp.Queue, так что вы в основном решили следующую проблему в очереди, спасибо! 😉

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

3. Извините, возможно, я неправильно объяснил себя. Первоначальная проблема заключалась в том, что процессы даже не запускались, что было исправлено с помощью spawn в качестве метода запуска. Как только я это сделал, я получил другую ошибку, связанную с использованием очередей (TypeError: не удается определить _thread . блокировка объектов)… Я решил эту последнюю проблему с помощью многопроцессорной обработки. Очередь вместо очереди. Очередь

4. Вы написали, что был вывод из обоих процессов, но print('Here') не был выполнен. Таким образом, процессы, должно быть, начались, возникла проблема связи с использованием queue.Queue вместо multiprocessing.Queue .

5. К сожалению, в разделе импорта была ошибка, как только я исправил это и использовал mp.Queues(), все прошло нормально, даже без запуска процессов. В моей (частичной) защите минимальный пример, который я опубликовал, был слишком minimal…in в реальной ситуации мне все еще нужно использовать set_start_method(«spawn»), чтобы запустить процессы. Я подозреваю, что это может быть связано с одним из процессов, использующих библиотеку глубокого обучения, которая уже реализует многопроцессорную обработку … может быть, это портит весь механизм? Мне нужно будет разобраться с этим .. в любом случае, спасибо!