You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Python脚本启动进程并获取PID:解决等待及客户端连接失败问题

解决子进程启动后客户端无法连接的问题

首先得说,你选subprocess.Popen()其实是完全正确的——因为subprocess.run()会一直等进程跑完才返回,根本没法满足你中途监控进程的需求。现在客户端连不上服务器的问题,大概率是子进程的IO缓冲区被占满,导致服务器进程被阻塞了

为什么会出现这个问题?

当你用Popen默认参数启动子进程时,它会继承父进程的标准输入、输出、错误流。如果你的服务器程序有日志输出(比如启动日志、连接日志),但父进程(也就是你的监控脚本)没有读取这些输出,当输出缓冲区被填满时,服务器进程就会暂停执行,自然没法处理新的socket连接请求了——这就是为什么你用ps aux能看到进程,但客户端连不上的核心原因。

解决办法:处理子进程的IO流

这里有两种常用的方案,根据你的需求选就行:

方案1:重定向IO到/dev/null或日志文件

如果你不需要看服务器的输出,最简单的办法就是把所有IO都重定向到/dev/null,避免缓冲区阻塞:

import subprocess
import time

# 启动子进程,重定向所有IO
p = subprocess.Popen(
    ["nameofmyprocess"],  # 推荐用列表形式传命令,避免shell注入风险
    stdout=subprocess.DEVNULL,
    stderr=subprocess.DEVNULL,
    stdin=subprocess.DEVNULL
)

pid = p.pid
print(pid)

# 循环监控直到进程退出
while p.poll() is None:
    time.sleep(20)
    myFunc(pid)
    myFunc2(pid)

如果需要保留服务器的日志,可以把输出写到文件里:

import subprocess
import time

# 把stdout和stderr都写到server.log里
with open("server.log", "a", encoding="utf-8") as log_file:
    p = subprocess.Popen(
        ["nameofmyprocess"],
        stdout=log_file,
        stderr=subprocess.STDOUT,  # 把错误输出合并到标准输出
        stdin=subprocess.DEVNULL
    )

pid = p.pid
print(pid)

while p.poll() is None:
    time.sleep(20)
    myFunc(pid)
    myFunc2(pid)

方案2:用线程实时读取子进程输出

如果需要实时查看服务器的输出(比如调试用),可以启动两个线程分别读取stdout和stderr,避免阻塞子进程:

import subprocess
import time
import threading

def read_stream(stream, stream_name):
    # 循环读取流内容
    for line in iter(stream.readline, ""):
        print(f"[{stream_name}] {line.strip()}")

# 启动子进程,开启管道获取输出
p = subprocess.Popen(
    ["nameofmyprocess"],
    stdout=subprocess.PIPE,
    stderr=subprocess.PIPE,
    stdin=subprocess.DEVNULL,
    text=True  # 用文本模式,自动处理编码
)

# 启动线程读取stdout和stderr
stdout_thread = threading.Thread(target=read_stream, args=(p.stdout, "STDOUT"))
stderr_thread = threading.Thread(target=read_stream, args=(p.stderr, "STDERR"))
stdout_thread.start()
stderr_thread.start()

pid = p.pid
print(pid)

# 监控进程
while p.poll() is None:
    time.sleep(20)
    myFunc(pid)
    myFunc2(pid)

# 等待线程结束
stdout_thread.join()
stderr_thread.join()

额外提醒

在你的myFuncmyFunc2里,最好加个判断:先检查PID对应的进程是否还存在(虽然循环里判断了p.poll() is None,但极端情况下进程可能在sleep期间退出),避免监控函数报错。比如可以用os.kill(pid, 0)来检查进程是否存在(需要导入os模块):

import os

def myFunc(pid):
    try:
        os.kill(pid, 0)  # 发送0号信号,不会终止进程,只是检查是否存在
        # 你的监控逻辑(内存、socket、文件描述符等)
    except OSError:
        print(f"Process {pid} no longer exists")
        return

内容的提问来源于stack exchange,提问作者hexlify

火山引擎 最新活动