Python 3.11在Windows上subprocess子进程无法正常退出求助
解决方案
针对Windows下Python 3.11启动Python 2.4编译的32位子进程后无法正常检测退出的问题,可尝试以下几种修复方式:
1. 重定向子进程标准流,避免IO阻塞
Windows下子进程若未正确处理标准输入/输出/错误流,可能导致进程退出时被挂起,主进程的poll()无法检测到状态变化。启动子进程时将这些流重定向到DEVNULL:
import subprocess import sys # Windows分支修改为: if sys.platform in ["win32", "win64"]: game = subprocess.Popen( "Game", creationflags=0x08000000, # 原CREATE_NO_WINDOW标记 stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, shell=False )
2. 使用Win32 API更可靠地等待进程退出
替换poll()循环为Win32的事件等待机制,避免Python subprocess模块在Windows下的兼容性问题:
import subprocess import sys import win32process import win32event if sys.platform in ["win32", "win64"]: # 新增CREATE_NEW_PROCESS_GROUP标记,确保进程组独立 game = subprocess.Popen("Game", creationflags=0x08000000 | 0x00000200) # 获取进程同步句柄 process_handle = win32process.OpenProcess(win32process.SYNCHRONIZE, False, game.pid) try: # 每1.5秒检查一次进程状态,避免阻塞主线程 while True: wait_result = win32event.WaitForSingleObject(process_handle, 1500) if wait_result != win32event.WAIT_TIMEOUT: break # 获取准确的退出码 return_code = win32process.GetExitCodeProcess(process_handle) finally: win32process.CloseHandle(process_handle)
3. 避免阻塞Qt主线程
原代码中的while循环+time.sleep会阻塞Qt主线程,可能导致进程状态检测异常。改用Qt的QTimer定期检查:
from PyQt5.QtCore import QTimer def launch_game(self): self.hide_progress_bar() # ... 启动子进程的代码 ... self.game_process = game # 将进程实例保存为类成员 self.showMinimized() self.setWindowFlags(self.windowFlags() & Qt.CustomizeWindowHint) self.setWindowFlags(self.windowFlags() & ~Qt.WindowMinMaxButtonsHint) # 启动定时器,每1.5秒检查一次进程状态 self.poll_timer = QTimer(self) self.poll_timer.timeout.connect(self._check_game_exit) self.poll_timer.start(1500) def _check_game_exit(self): if self.game_process.poll() is not None: self.poll_timer.stop() self.restore_window() if self.game_process.returncode == 0: self.update_status("Thanks for playing!") else: self.update_status_error("An unexpected error occurred.")
4. 检查子进程是否残留子进程
若Game进程退出时未清理自身启动的子进程,会导致主进程误判其仍在运行。可尝试在检测到Game进程退出后,强制终止其关联的进程树(仅作为最后手段):
import psutil def kill_process_tree(pid): try: parent = psutil.Process(pid) children = parent.children(recursive=True) for child in children: child.kill() parent.kill() except psutil.NoSuchProcess: pass # 在检测到进程异常时调用: # kill_process_tree(game.pid)
内容的提问来源于stack exchange,提问作者Mysterious Ghost
相关产品推荐
相关产品推荐

