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

如何在Pygame中使用多进程加速百万矩形绘制?

优化百万矩形绘制速度的方案

核心限制说明

PyGame底层依赖的SDL渲染上下文是单线程安全的,不能直接在多线程中调用绘制API操作主屏幕Surface,否则会导致渲染错乱或程序崩溃。因此不能直接照搬OpenMP的并行绘制思路,需要换用「并行预处理离屏渲染+主屏幕合并」的方案。


1. 基础优化:减少冗余开销与启用硬件加速

先从代码结构和渲染模式入手,砍掉不必要的对象封装开销,同时开启PyGame硬件加速:

import pygame
from random import randint

pygame.init()
# 开启硬件加速与双缓冲,提升渲染效率
screen = pygame.display.set_mode((640, 480), pygame.HWSURFACE | pygame.DOUBLEBUF)
screen.fill((0,0,0))

# 直接存储矩形参数元组,避免类属性访问开销
rects_data = []
for _ in range(1000000):
    color = (randint(0,255), randint(0,255), randint(0,255))
    pos = (randint(0, 639), randint(0, 479))
    width = 639 - randint(pos[0], 639)
    height = 479 - randint(pos[1], 479)
    rects_data.append((color, pos, (width, height)))

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            exit()
    
    screen.fill((0,0,0))
    # 直接遍历参数绘制,减少对象调用开销
    for color, pos, size in rects_data:
        pygame.draw.rect(screen, color, pygame.Rect(pos, size))
    pygame.display.flip()

2. 并行分块渲染:利用多线程预处理离屏Surface

将屏幕划分为多个区域,每个区域在单独线程中渲染到离屏Surface,最后合并到主屏幕,充分利用多CPU核心:

import pygame
from random import randint
from concurrent.futures import ThreadPoolExecutor

pygame.init()
screen_width, screen_height = 640, 480
screen = pygame.display.set_mode((screen_width, screen_height), pygame.HWSURFACE | pygame.DOUBLEBUF)
screen.fill((0,0,0))

# 预处理所有矩形参数
rects_data = []
for _ in range(1000000):
    color = (randint(0,255), randint(0,255), randint(0,255))
    pos = (randint(0, screen_width-1), randint(0, screen_height-1))
    width = screen_width - 1 - randint(pos[0], screen_width-1)
    height = screen_height - 1 - randint(pos[1], screen_height-1)
    rects_data.append((color, pos, (width, height)))

# 单块渲染函数:只处理指定区域内的矩形
def render_block(block_rect):
    block_surf = pygame.Surface((block_rect.width, block_rect.height))
    block_surf.fill((0,0,0))
    # 筛选当前块内的矩形并绘制
    for color, pos, size in rects_data:
        rect = pygame.Rect(pos, size)
        if rect.colliderect(block_rect):
            # 转换为块Surface的局部坐标
            local_pos = (pos[0] - block_rect.x, pos[1] - block_rect.y)
            pygame.draw.rect(block_surf, color, pygame.Rect(local_pos, size))
    return block_rect, block_surf

# 按CPU核心数划分屏幕块(示例为4块)
num_blocks = 4
block_width = screen_width // num_blocks
blocks = [pygame.Rect(i*block_width, 0, block_width, screen_height) for i in range(num_blocks)]

# 创建线程池
executor = ThreadPoolExecutor(max_workers=num_blocks)

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            executor.shutdown()
            pygame.quit()
            exit()
    
    # 并行渲染所有块
    futures = [executor.submit(render_block, block) for block in blocks]
    # 将渲染好的块合并到主屏幕
    for future in futures:
        block_rect, block_surf = future.result()
        screen.blit(block_surf, block_rect.topleft)
    
    pygame.display.flip()

3. 极致优化:直接操作像素数组

跳过PyGame的draw.rectAPI开销,用pygame.surfarray直接操作屏幕像素缓冲区,速度提升最明显:

import pygame
from random import randint
import numpy as np

pygame.init()
screen_width, screen_height = 640, 480
screen = pygame.display.set_mode((screen_width, screen_height), pygame.HWSURFACE | pygame.DOUBLEBUF)
# 获取屏幕的numpy像素数组,直接操作像素
screen_array = pygame.surfarray.pixels3d(screen)

# 预处理矩形的坐标范围与颜色
rects_data = []
for _ in range(1000000):
    color = (randint(0,255), randint(0,255), randint(0,255))
    x1, y1 = randint(0, screen_width-1), randint(0, screen_height-1)
    x2 = screen_width - 1 - randint(x1, screen_width-1)
    y2 = screen_height - 1 - randint(y1, screen_height-1)
    rects_data.append((x1, y1, x2, y2, color))

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            exit()
    
    # 清空屏幕像素
    screen_array[:] = 0
    # 直接给矩形区域填充颜色
    for x1, y1, x2, y2, (r,g,b) in rects_data:
        # 确保坐标不超出屏幕范围
        x1_clamp = max(0, x1)
        x2_clamp = min(screen_width, x2)
        y1_clamp = max(0, y1)
        y2_clamp = min(screen_height, y2)
        if x1_clamp >= x2_clamp or y1_clamp >= y2_clamp:
            continue
        # 批量设置像素颜色
        screen_array[y1_clamp:y2_clamp, x1_clamp:x2_clamp] = (r, g, b)
    
    pygame.display.flip()

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 15:57:16