You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 12:52:45