如何设置Subprocess.Popen不等待进程完成即可运行后续代码
问题原因
你遇到的阻塞问题本质是两类原因:一是直接调用Popen.communicate()这类方法会等待进程终止才返回;二是管道默认的块缓冲机制会导致输出攒到固定大小才返回给调用方,给人“阻塞到进程结束才输出”的错觉。
解决方案1:线程独立处理输出(兼容所有Python环境,最通用)
核心思路是将子进程输出读取逻辑放到独立线程运行,主线程可正常执行其他业务逻辑,二者互不干扰。
完整示例代码
import subprocess import threading def read_server_output(process, output_callback): # 迭代读取输出行,遇到空字节时终止(进程已退出) for line in iter(process.stdout.readline, b""): # 可根据服务器实际编码调整,Windows环境常用gbk/utf-8,忽略解码错误避免程序崩溃 decoded_line = line.decode("utf-8", errors="ignore").strip() output_callback(decoded_line) process.stdout.close() def Start(): # 命令拆分为列表形式,后续关闭shell=True时可直接复用 cmd = ["ArkServer.exe", "-ArgumentsHere"] server_proc = subprocess.Popen( cmd, stdout=subprocess.PIPE, # 合并错误输出到stdout,避免遗漏错误日志,需分开采集可删掉本行后单独读stderr stderr=subprocess.STDOUT, stdin=subprocess.PIPE, shell=True, # 测试临时使用,后续切换为False即可 bufsize=1 # 开启行缓冲,降低输出延迟 ) # 自定义输出处理逻辑,可自行扩展日志存储、关键词监控等功能 def handle_output(line): print(f"[Ark服务器日志] {line}", flush=True) # 示例:匹配启动完成关键词触发后续操作 # if "Server started successfully" in line: # do_something() # 启动守护线程读输出,主线程退出时线程自动销毁 output_thread = threading.Thread( target=read_server_output, args=(server_proc, handle_output), daemon=True ) output_thread.start() # 此处可编写其他业务逻辑,比如给服务器发送指令 # server_proc.stdin.write(b"saveworld\n") # server_proc.stdin.flush() return server_proc, output_thread
注意事项
- 不要直接调用
server_proc.communicate(),该方法会阻塞到子进程完全退出才返回,不符合实时采集需求 - 如需分开采集stdout和stderr,单独启动另一个线程读取
process.stderr即可,不要在同一个线程交替读取两个管道,容易触发死锁 - 后续关闭
shell=True时,仅需将参数改为shell=False,命令保持列表形式即可,无需修改其他逻辑
解决方案2:异步IO实现(适合基于asyncio的项目)
如果你的项目已经用了异步技术栈,可以用asyncio原生的子进程API实现无阻塞读取,无需手动管理线程:
import asyncio async def start_ark_server(): proc = await asyncio.create_subprocess_exec( "ArkServer.exe", "-ArgumentsHere", stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.STDOUT ) # 异步读取输出 async def read_server_log(): while True: line = await proc.stdout.readline() if not line: break log_content = line.decode("utf-8", errors="ignore").strip() print(f"[Ark服务器日志] {log_content}") # 创建异步任务运行日志读取,不阻塞其他协程 asyncio.create_task(read_server_log()) # 此处可运行其他异步业务逻辑 await proc.wait()
内容的提问来源于stack exchange,提问作者Zulvex
相关产品推荐
相关产品推荐

