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

Python中如何通过subprocess.Popen传递变量并终止子进程循环?

解决Python子进程录屏的两个问题(Windows环境)

问题1:正确传递video_name到子进程

错误原因排查

用sys.argv[1]失败大概率是主进程传参格式错误,或子进程接收逻辑有误;用stdin则可能是子进程未正确读取输入流,或主进程写入后未关闭流导致子进程阻塞。

正确的命令行传参实现

主进程代码:

import subprocess
import sys

video_name = "my_recording.mp4"
# 用sys.executable获取当前环境的Python解释器路径,避免环境冲突
proc = subprocess.Popen(
    [sys.executable, "ScreenRecorder.py", video_name],
    stdout=subprocess.PIPE,
    stderr=subprocess.PIPE,
    text=True
)

子进程ScreenRecorder.py接收参数:

import sys

# 优先使用传入的参数,无参数时用默认值
if len(sys.argv) >= 2:
    video_name = sys.argv[1]
else:
    video_name = "default_recording.mp4"

# 后续录屏逻辑直接使用video_name变量

验证要点

  • 主进程必须用列表形式传参,不要把命令拼成字符串(Windows下易因空格、特殊字符出问题)
  • 确保ScreenRecorder.py和主脚本在同一目录,或传入脚本的绝对路径
  • 可在子进程开头打印参数确认:print(f"Received video name: {sys.argv[1]}")

问题2:主进程发送信号让子进程正常收尾

Windows下Python的signal模块支持有限,无法直接用SIGINT类信号优雅终止,推荐用管道通信或文件标志位实现,让子进程主动检测终止信号,退出循环后执行收尾代码。

方案1:管道通信(推荐)

主进程代码:

import subprocess
import sys
import time

video_name = "my_recording.mp4"
# 创建双向管道,支持主进程向子进程发送指令
proc = subprocess.Popen(
    [sys.executable, "ScreenRecorder.py", video_name],
    stdin=subprocess.PIPE,
    stdout=subprocess.PIPE,
    stderr=subprocess.PIPE,
    text=True
)

# 模拟主业务逻辑,15秒后发送终止指令
time.sleep(15)
proc.stdin.write("stop\n")
proc.stdin.flush()  # 必须刷新缓冲区,否则子进程收不到指令

# 等待子进程执行完收尾代码,获取输出
stdout, stderr = proc.communicate()
print("子进程输出:", stdout)
if stderr:
    print("子进程错误:", stderr)

子进程ScreenRecorder.py代码:

import sys
import cv2
import numpy as np
from PIL import ImageGrab
import select

video_name = sys.argv[1] if len(sys.argv)>=2 else "default.mp4"

# 初始化录屏参数
screen_size = (1920, 1080)
fourcc = cv2.VideoWriter_fourcc(*"mp4v")
out = cv2.VideoWriter(video_name, fourcc, 20.0, screen_size)

running = True
while running:
    # 捕获屏幕帧并写入视频
    img = ImageGrab.grab(bbox=(0, 0, screen_size[0], screen_size[1]))
    frame = np.array(img)
    frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
    out.write(frame)

    # 非阻塞检测stdin的终止指令
    ready, _, _ = select.select([sys.stdin], [], [], 0.01)
    if ready:
        line = sys.stdin.readline().strip()
        if line == "stop":
            running = False

# 循环结束后执行收尾代码
out.release()
cv2.destroyAllWindows()
print(f"视频已保存为:{video_name}")

方案2:文件标志位(简单易实现)

主进程代码:

import subprocess
import sys
import time
import os

video_name = "my_recording.mp4"
stop_flag_file = "stop_recording.flag"

# 确保标志文件不存在
if os.path.exists(stop_flag_file):
    os.remove(stop_flag_file)

proc = subprocess.Popen(
    [sys.executable, "ScreenRecorder.py", video_name, stop_flag_file],
    stdout=subprocess.PIPE,
    stderr=subprocess.PIPE,
    text=True
)

# 15秒后创建标志文件,触发子进程终止
time.sleep(15)
with open(stop_flag_file, "w") as f:
    f.write("1")

# 等待子进程完成并清理标志文件
stdout, stderr = proc.communicate()
if os.path.exists(stop_flag_file):
    os.remove(stop_flag_file)
print(stdout)

子进程ScreenRecorder.py代码:

import sys
import cv2
import numpy as np
from PIL import ImageGrab
import os

video_name = sys.argv[1] if len(sys.argv)>=2 else "default.mp4"
stop_flag_file = sys.argv[2] if len(sys.argv)>=3 else "stop_recording.flag"

screen_size = (1920, 1080)
fourcc = cv2.VideoWriter_fourcc(*"mp4v")
out = cv2.VideoWriter(video_name, fourcc, 20.0, screen_size)

running = True
while running:
    img = ImageGrab.grab(bbox=(0, 0, screen_size[0], screen_size[1]))
    frame = np.array(img)
    frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
    out.write(frame)

    # 检测标志文件是否存在,存在则终止循环
    if os.path.exists(stop_flag_file):
        running = False

# 收尾代码
out.release()
cv2.destroyAllWindows()
print(f"视频已保存:{video_name}")

注意事项

  • 管道方案中,若select模块在Windows下出现问题,可替换为每隔10帧尝试读取一次stdin,避免阻塞
  • 无论用哪种方案,子进程的循环都要定期检测终止信号,避免长时间阻塞导致收不到指令
  • 主进程必须用proc.communicate()等待子进程执行完收尾代码,不要直接强制杀死进程

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 03:55:39