Сейчас я занимаюсь разработкой приложение для обработки изображений, которое должно работать как на Windows 11, так и на OrangePi5 с Debian Linux. Моя установка такова, что помимо основной программы есть два других процесса: один для обработки непрерывного нажатия кнопок и других операций ввода-вывода, а другой для отделения функций камеры от остальной части app.
Оба класса, которые содержат эти процессы, имеют одинаковые функции многопроцессорной обработки:
- Имеется три очереди.
Очередь данных содержит один кортеж с основным выводом класса. Данные помещаются в него периодически, и в любой момент времени существует максимум один кортеж. Основная программа либо получает то, что есть, либо использует значения по умолчанию. - Очередь конфигурации используется для отправки кортежей с именами методов конфигурации и соответствующими аргументами рабочему процессу.< /li>
Очередь состояний используется для получения подтверждения настроек конфигурации от рабочего процесса.
[*]Оба класса имеют методы start_process и stop_process.
- Метод start инициализирует поля, связанные с многопроцессорной обработкой, и запускает рабочий процесс с помощью события инициализации.
- Метод stop устанавливает событие остановки, пытается присоединиться к рабочему процессу, и если это не работает, он завершает его и рекурсивно вызывает себя, чтобы записать подробности о том, был ли и как процесс остановлен.
Проблема в том, что, хотя процесс присоединения кнопки выполняется без проблем (когда я устанавливаю тайм-аут соединения 0,1 с или больше), камере всегда приходится быть прекращено, независимо от того, как долго я делаю тайм-аут присоединения, он никогда не присоединяется. Я думал, что, поскольку ответы камеры иногда могут быть очень затратными по времени, может потребоваться слишком много времени, чтобы распознать, что событие остановки было установлено, но мне неоднократно удавалось поймать остановку процесса с помощью соединение по-прежнему не удается.
Это происходит одинаково в обеих операционных системах, как когда классы используются сами по себе, так и друг с другом. Я начинаю думать, что неосознанно блокирую некоторые ресурсы, из-за чего работник камеры становится недоступным, но понятия не имею, как можно это устранить. Кнопка отправляет различные виды неизменяемых значений, камера отправляет одно или два изображения np.array (она получает их как image.copy()) и либо None, либо Exception.
Любой толчок в правильном направлении, будь то в отношении того, что именно может быть причиной этого или того, как я мог бы точно определить, что именно мешает процессу присоединиться, был бы очень признателен. Заранее спасибо!
Процесс кнопки (присоединяется без проблем)
Код: Выделить всё
def _worker_process(self) -> None:
try:
while not self._stop_event.is_set():
if not self._is_parent_alive():
break
if not self._config_queue.empty():
config_message: tuple = self._config_queue.get()
self._apply_config(config_message)
is_pressed: bool = self._button.check_if_pressed()
button_state_from_info, time_until_long_press = self._button.get_button_info(is_pressed)
# Determine if the state should be updated
state_idx: int = self._button_state_map.get(button_state_from_info, -1)
update_state: bool = False
# Button state pattern matching and state change record update here
...
self._clear_queue(self._data_queue)
self._data_queue_send(self._worker_but_st, time_until_long_press, st_ch_rec_tuple)
time.sleep(0.05)
except Exception:
full_traceback = traceback.format_exc()
self._clear_queue(self._data_queue)
self._data_queue_send(exception=full_traceback)
Код: Выделить всё
def _worker_process(self) -> None:
try:
while not self._stop_event.is_set():
if not self._is_parent_alive():
break
if not self._config_queue.empty():
config_message: tuple = self._config_queue.get()
self._apply_config(config_message)
# Capture image(s)
self.camera.capture()
# Get the latest captured images based on exposure mode
if self.camera.exp_mode == ExposureMode.SINGLE_EXP:
latest_img_loexp = self.camera.get_last_img().copy()
latest_img_hiexp = None
elif self.camera.exp_mode == ExposureMode.DOUBLE_EXP:
latest_img_loexp = self.camera.get_last_img_loexp().copy()
latest_img_hiexp = self.camera.get_last_img_hiexp().copy()
else:
raise ValueError(f"Exposure mode ({self.camera.exp_mode}) either invalid or not recognised.")
self._clear_queue(self._data_queue)
self._data_queue_send(latest_img_loexp, latest_img_hiexp, None)
time.sleep(0.05)
except Exception:
full_traceback = traceback.format_exc()
self._clear_queue(self._data_queue)
self._data_queue_send(exception=full_traceback)
Код: Выделить всё
def stop_process(self, is_recursive_call=False) -> None:
self._stop_event.set()
if self._process is not None and self._process.is_alive():
try:
self._process.join(timeout=0.2)
# If the process is still alive and this is not a recursive call, terminate and retry
if self._process.is_alive() and not is_recursive_call:
print(f"{self.CLASS_NAME}: Failed to join worker process, terminating.")
self._process.terminate()
self.stop_process(is_recursive_call=True)
else:
self._report_on_stop_attempt()
except KeyboardInterrupt as e:
print(f"{self.CLASS_NAME}: KeyboardInterrupt in process joining, joining failed.")
raise e
elif self._process and not self._process.is_alive():
print(f"{self.CLASS_NAME}: Unexpected stop behavior - process was not alive "
f"on 'stop_process' ({self._process=}).")
else:
print(f"{self.CLASS_NAME}: Unexpected stop behavior - process was None.")
Подробнее здесь: https://stackoverflow.com/questions/788 ... processing
Мобильная версия