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

Python multiprocessing多进程下模块重复导入引发pygame提示重复打印问题

多进程pygame截图程序问题修复

1. pygame欢迎信息重复打印问题

  • 触发原因:Windows系统下Pythonmultiprocessing默认采用spawn模式创建子进程,每个子进程启动时会独立导入主模块依赖的所有库。当前程序共启动3个独立进程:主进程、截图子进程、显示子进程,每个进程首次导入pygame时都会触发一次内置的欢迎信息打印,因此控制台会累计输出3次相同内容。
  • 性能影响:该现象不会产生额外的系统资源消耗,对程序运行性能无任何影响。欢迎信息是pygame导入阶段执行的一次性控制台文本输出,仅在进程启动的极短时间内运行,程序进入截图、渲染循环后不会重复触发,不会影响帧率、CPU/内存占用。
  • 隐藏方法:若需要关闭该提示,在所有pygame相关导入语句前添加如下配置即可:
import os
os.environ['PYGAME_HIDE_SUPPORT_PROMPT'] = '1'

2. 关闭窗口后进程残留无法退出问题

  • 触发原因:
    • 启动子进程时未保存进程实例,也未设计跨进程退出通知逻辑:截图进程运行的是无退出条件的死循环,显示窗口关闭、显示进程退出后,截图进程仍会持续执行截图、往队列写入数据的操作,成为不会自动退出的孤儿进程。
    • 主进程启动子进程后未配置进程等待、回收逻辑,无法感知窗口关闭事件,也不会主动终止残留进程。
    • 原代码中队列未设置长度上限,当渲染速度跟不上截图速度时会出现帧数据堆积,进一步加剧进程退出阻塞、画面延迟问题。
  • 修复点说明:
    • 为消息队列设置最大长度,队列满时主动丢弃最早的未渲染帧,避免内存堆积和高延迟
    • 将截图进程设置为守护进程,主进程退出时可自动终止该进程
    • 保存子进程实例引用,主进程阻塞等待显示进程运行结束,显示进程退出后主动检查、终止残留的截图进程,回收系统资源
    • 队列读取操作增加超时逻辑,避免队列阻塞导致进程无法正常响应退出信号
  • 修复后完整代码:
import os
os.environ['PYGAME_HIDE_SUPPORT_PROMPT'] = '1'
from mss import mss
from multiprocessing import Process, Queue
import pygame
import pygame.display
import pygame.image
import pygame.time
import pygame.font
import pygame.event
from pygame.locals import *
from numpy import asarray
from cv2 import resize, cvtColor, COLOR_BGRA2BGR

SCR_SIZE = (640, 480)

def grabber(queue: Queue):
    global SCR_SIZE
    with mss() as sct:
        while True:
            # 队列满时丢弃旧帧,保证画面实时性
            if queue.full():
                try:
                    queue.get_nowait()
                except:
                    pass
            frame = cvtColor(
                resize(asarray(sct.grab(sct.monitors[1])), SCR_SIZE),
                COLOR_BGRA2BGR
            ).tobytes()
            queue.put(frame)

def displayer(queue: Queue):
    global SCR_SIZE
    pygame.init()
    SCR = pygame.display.set_mode(SCR_SIZE, DOUBLEBUF)
    SCR.set_alpha(None)
    clock = pygame.time.Clock()
    FONT_COMIC = pygame.font.SysFont('Cambria Math', 20)
    is_running = True
    while is_running:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                is_running = False
        clock.tick(60)
        current_frame = None
        try:
            current_frame = queue.get(timeout=0.1)
        except:
            pass
        if current_frame is not None:
            SCR.blit(pygame.image.frombuffer(current_frame, SCR_SIZE, 'BGR'), (0,0))
        SCR.blit(
            FONT_COMIC.render(f'FPS:{str(clock.get_fps())[:5]}', False, (0,255,0)),
            (10,10)
        )
        pygame.display.update()
    pygame.quit()

if __name__ == "__main__":
    # 限制队列最大长度为5,避免帧堆积
    frame_queue = Queue(maxsize=5)
    # 截图进程设为守护进程,主进程退出时自动终止
    p_grab = Process(target=grabber, args=(frame_queue,), daemon=True)
    p_disp = Process(target=displayer, args=(frame_queue,))
    p_grab.start()
    p_disp.start()
    # 等待显示窗口进程退出
    p_disp.join()
    # 兜底终止截图进程,避免残留
    if p_grab.is_alive():
        p_grab.terminate()
        p_grab.join()

内容的提问来源于stack exchange,提问作者Muhammad Ikhwan Perwira

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 07:21:21