Python multiprocessing多进程下模块重复导入引发pygame提示重复打印问题
多进程pygame截图程序问题修复
1. pygame欢迎信息重复打印问题
- 触发原因:Windows系统下Python
multiprocessing默认采用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
相关产品推荐
相关产品推荐

