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

Chunk快速创建性能优化求助:现有Python实现速度慢,求改进方案

Chunk创建功能的性能优化思路

我正在实现Chunk创建功能,目前功能可用但运行速度较慢,以下是具体实现步骤:

1. 定义立方体基础数据

vertices = [(-block_size / 2, -block_size / 2, block_size / 2),
            (block_size / 2, -block_size / 2, block_size / 2), (block_size / 2, block_size / 2, block_size / 2),
            (-block_size / 2, block_size / 2, block_size / 2),
            (-block_size / 2, block_size / 2, -block_size / 2),
            (-block_size / 2, -block_size / 2, -block_size / 2),
            (block_size / 2, -block_size / 2, -block_size / 2),
            (block_size / 2, block_size / 2, -block_size / 2)]

indices = [(0, 2, 3), (0, 1, 2),
           (1, 7, 2), (1, 6, 7),
           (6, 5, 4), (4, 7, 6),
           (3, 4, 5), (3, 5, 0),
           (3, 7, 4), (3, 2, 7),
           (0, 6, 1), (0, 5, 6)]

tex_coord_vertices = [(0, 0), (1, 0), (1, 1), (0, 1)]
tex_coord_indices = [(0, 2, 3), (0, 1, 2),
                     (0, 2, 3), (0, 1, 2),
                     (0, 1, 2), (2, 3, 0),
                     (2, 3, 0), (2, 0, 1),
                     (0, 2, 3), (0, 1, 2),
                     (3, 1, 2), (3, 0, 1), ]

normals = [(0, 0, 1) * 6,
           (1, 0, 0) * 6,
           (0, 0, -1) * 6,
           (-1, 0, 0) * 6,
           (0, 1, 0) * 6,
           (0, -1, 0) * 6, ]
normals = np.array(normals, dtype='f4').reshape(36, 3)

2. 生成2f 3f 3f格式的数据集

def get_data(vertices, indices):
    data = [vertices[ind] for triangle in indices for ind in triangle]
    return np.array(data, dtype='f4')
vertex_data_local = self.get_data(vertices, indices)
tex_coord_data = self.get_data(tex_coord_vertices, tex_coord_indices)
vertex_data_local = np.hstack([normals, vertex_data_local])
vertex_data_local = np.hstack([tex_coord_data, vertex_data_local])

3. 创建Chunk中立方体中心坐标数组

chunk_size = Settings.CHUNK_SIZE * Settings.CHUNK_SIZE * Settings.CHUNK_SIZE
coords = np.empty([chunk_size, 8])

index = 0
for x in range(Settings.CHUNK_SIZE):
    for y in range(Settings.CHUNK_SIZE):
                for z in range(Settings.CHUNK_SIZE):
                    if self.m_pBlocks[x][y][z].is_active():
                        coords[index] = (0, 0, 0, 0, 0, x * block_size, y * block_size, z * block_size)
                        index = index + 1

4. 生成Chunk数据数组

vertex_data = np.empty([chunk_size * 36, 8])
index = 0
for idx, obj in enumerate(coords):
    for ind, obj_row in enumerate(vertex_data_local):
        # print(np.add(arr, obj_row))
        vertex_data[index] = np.add(obj, obj_row)
        index = index + 1
vertex_data = np.array(vertex_data, dtype='f4')

目前已知可通过编写C语言库进行优化,请问还有其他可行的性能优化思路吗?


可行的性能优化思路

1. 面剔除:只生成可见面的顶点数据

当前实现会生成每个立方体的全部6个面,但多数面会被相邻的active方块遮挡。遍历每个active方块时,检查上下左右前后六个方向是否存在相邻的active方块,仅生成无遮挡的可见面数据,能直接减少50%-70%的顶点数据量,从根源降低计算和内存开销。

2. 用numpy向量化操作替代Python嵌套循环

Python循环的开销远高于numpy的底层C实现,重构步骤3和4:

  • 步骤3优化:利用meshgrid生成坐标网格,结合布尔索引筛选active方块,避免手动循环计数:
# 生成Chunk内所有方块的坐标网格
x_coords = np.arange(Settings.CHUNK_SIZE) * block_size
y_coords = np.arange(Settings.CHUNK_SIZE) * block_size
z_coords = np.arange(Settings.CHUNK_SIZE) * block_size
xx, yy, zz = np.meshgrid(x_coords, y_coords, z_coords, indexing='ij')

# 将方块active状态转为numpy布尔数组
active_mask = np.array([[[self.m_pBlocks[x][y][z].is_active() for z in range(Settings.CHUNK_SIZE)]
                         for y in range(Settings.CHUNK_SIZE)]
                        for x in range(Settings.CHUNK_SIZE)])

# 构造active方块的coords数组
active_xx = xx[active_mask]
active_yy = yy[active_mask]
active_zz = zz[active_mask]
coords = np.zeros((len(active_xx), 8), dtype='f4')
coords[:,5] = active_xx
coords[:,6] = active_yy
coords[:,7] = active_zz
  • 步骤4优化:利用numpy广播机制,一次性完成所有坐标的加法运算,彻底移除嵌套循环:
# 扩展维度后广播相加,再展平为最终数组
vertex_data = (coords[:, np.newaxis, :] + vertex_data_local[np.newaxis, :, :]).reshape(-1, 8).astype('f4')

3. 预计算静态数据

vertex_data_local仅与block_size相关,无需每次生成Chunk时重复计算。在程序初始化阶段预计算并缓存该数组,后续直接复用,省去get_data调用和数组拼接的开销。

4. 优化方块状态存储

将self.m_pBlocks的三维对象数组替换为numpy布尔数组(np.bool_类型),直接通过active_blocks[x,y,z]判断方块是否激活,避免频繁的对象属性访问开销。若追求极致内存效率,还可使用位掩码(用整数的每个bit表示一个方块的激活状态)。

5. 多核并行处理

对于大尺寸Chunk,可将其划分为多个子区域,用multiprocessing或concurrent.futures实现并行生成数据,充分利用CPU多核资源。注意需与numpy自身的多线程优化(如MKL/OpenBLAS)做好兼容,避免资源竞争。

6. 按需分配内存

步骤3中预先分配整个Chunk大小的coords数组会浪费内存(多数方块可能未激活),改为先收集激活方块的坐标,再按需分配内存,或用列表临时存储后转numpy数组(需权衡列表转数组的开销)。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 13:15:56