首页 > 解决方案 > os.system 和 subprocess.run 使我的多线程进程冻结,直到调用结束

问题描述

我是 python 新手,遇到了一些问题。

我编写了一个 update_manager 类,它可以通过 Tcp 与用户进行通信并预先安装不同的组件。

我的 update_manager 类使用 2 个其他类(它们是他的成员)来完成此操作。第一个用于 TCP 通信,第二个用于实际安装。安装类从主线程运行,通信使用 Threading.thread() 函数运行。

我的主要锁是这样的:

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() 在线程之间和用户之间进行同步。一个用于传入消息,一个用于传出消息。

起初 TCP 通信是同步的,用户提供安装文件和其他一些东西。

一旦安装开始,TCP 通信就不再同步。

在安装过程中,我使用了 4 种不同的安装方法。并且除了一个之外的所有工作都没有问题(用户可以汇集 update_manager 进程并询问进度问题并立即得到答复)

有问题的一个是 rpm 文件的实例化。为此,我尝试调用 os.system() 和 subprocess.run() 并且它可以工作,但是对于大 rpm 文件,我注意到整个进程与我的线程冻结,直到调用完成(我可以看到我的 rpm 安装的进度条在此冻结期间的屏幕)。

我注意到并尝试的: 1.在其他使用python的安装方法期间没有冻结。图书馆。

2.一旦用户通过 TCP 连接,update_manager 只有 2 个线程,一旦发送第一个请求并发送回回复,就会出现另外 2 个线程(我假设它与我使用的队列有关)。

3.我创建了第三个打印时间的线程(与队列无关),我在 update_manager 进程启动后立即启动它。当 2 个线程冻结时,这个线程会继续运行。

4.在极少数情况下,进程会解冻,只是为了让消息从客户端发送到 update_manager 并冻结回来。

编辑:我忘记了更重要的一点 5. 调用时发生冻结: os.system("rpm --nodeps --force -ivh rpm_file_name")

但是调用时不会发生: os.system("sleep 5")

我真的很感激一些穷人,谢谢。

标签: pythonmultithreadingsubprocessmessage-queue

解决方案


问题在于传入队列。

我用了:

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

推荐阅读