os.system и subprocess.run заставляют мой многопоточный процесс зависать до завершения вызова - PullRequest
1 голос
/ 03 августа 2020

Я новичок в python и у меня есть некоторые проблемы.

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

Мой класс update_manager использует 2 других класса (они его члены), чтобы выполнить sh это. Первый используется для связи TCP, а второй - для фактической установки. класс установки запускается из основного потока, а взаимодействие осуществляется с помощью функции Threading.thread ().

my main блокируется следующим образом:

if __name__ == "__main__":
    new_update = UpdateManager()

    #time.sleep(10)
    new_update.run()

и функции запуска:

def run(self):

    comm_thread = threading.Thread(target=  
                  self._comm_agent.start_server_tcp_comunication)
                  comm_thread.start()

    while True:

        if (False == self.is_recovery_required()):

            self.calculate_free_storage_for_update_zip_extraction()
            self.start_communication_with_client_in_state_machine()

        self._comm_agent.disable_synchronized_communication()
        self.start_update_install()
        self._comm_agent.enable_synchronized_communication()

        if (True == self.is_dry_run_requested()):
            self.preform_cleanup_after_dry_run()
            
        else:
            self.reset_valid_states()
            self.preform_clean_up_after_update_cycle()

Я использую 2 multiprocessing.Queue () для синхронизации c между потоками и между пользователем. Один для входящих сообщений и один для исходящих.

Сначала TCP-связь является синхронной, пользователь предоставляет установочный файл и некоторые другие вещи.

После начала установки TCP-связь перестает быть синхронной.

Во время установки я использую 4 разных метода установки. и все, кроме одного, работают нормально, без проблем (пользователь может объединить процесс update_manager и задавать вопросы о ходе выполнения и немедленно получить ответ)

Проблема c одна - это создание экземпляров файлов rpm. для этого я попытался вызвать os.system () и subprocess.run (), и он работает, но для больших файлов rpm я замечаю, что весь процесс с моими потоками зависает до завершения вызова (я вижу индикатор выполнения установки rpm на моем экран во время этого зависания).

Что я заметил и попробовал: 1. Нет зависания во время других методов установки, использующих python. библиотеки.

2. Как только пользователь подключается через TCP, для update_manager остается только 2 потока, после отправки первого запроса и отправки ответа появляются еще 2 потока (я предполагаю, что это как-то связано с очередями Я использую).

3. Я создал третий поток, который печатает время (и не имеет ничего общего с очередями), и запускаю его, как только запускается процесс update_manager. Когда 2 потока замораживаются, этот продолжает работать.

4. В некоторых редких случаях процесс размораживается только для сообщения go, которое передается от клиента к update_manager и возвращается обратно.

Edit: Забыл еще один важный момент 5. Зависание происходит при вызове: os.system ("rpm --nodeps --force -ivh rpm_file_name")

Но не происходит при вызове: os.system ("sleep 5 ")

Я был бы очень признателен некоторым нуждающимся, спасибо.

1 Ответ

0 голосов
/ 27 августа 2020

Проблема была во входящей очереди.

Я использовал:

if (True == self._outgoing_message_queue.empty()):
    temp: dict = self._outgoing_message_queue.get()

Это простая ошибка, поток просто застрял в пустой очереди.

Но даже если код изменить на

if (False == self._outgoing_message_queue.empty()):
    temp: dict = self._outgoing_message_queue.get()

, это может вызвать такое же поведение, потому что между моментом выполнения оператора if и моментом вызова get () может произойти переключение контактов, и очередь может станет пустым, и поток застрянет на .get (), как в моем исходном коде.

Лучшее решение - использовать get_nowait ()

try:
    temp = self._outgoing_message_queue.get_nowait()
except:
    temp = None
...