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

Python/PyPy模拟程序运行过慢,求不改变p[i]结构的优化方案

模拟程序性能优化方案

核心性能瓶颈排查

现有代码的性能损耗主要集中在以下几类冗余操作上:

  • 反复遍历全列表统计状态:每次循环调用4次population_list.count(),相当于每次要遍历整个千万级人口列表4次,时间复杂度直接翻4倍
  • 不必要的序列化操作:旧版本代码中str(p[i]).count("1")会先把整个列表序列化成字符串再统计,开销是直接列表count的几十倍
  • 遍历列表时执行删除操作:p[i].pop(j)会导致列表后续元素全部前移,每删一个元素就要遍历一次剩余列表,数据量大的时候开销爆炸
  • 无效的LRU缓存装饰:simulation()函数没有输入参数,lru_cache完全不会生效,属于无效装饰还额外增加了调用开销
  • 重复计算不变量:所有固定概率参数不需要每次循环都重新计算

可落地的优化方案

1. 替换全列表遍历统计,用变量实时维护状态

不要每次都调用count()统计健康、感染、康复人数,直接在修改人口状态的时候同步更新对应计数:

# 初始化的时候就定义计数变量
infected_cnt = 1
healthy_cnt = 99999999
recovered_cnt = 0
alive_cnt = 100000000

每次有人感染、康复、死亡的时候直接加减对应变量,完全省去每次循环的4次全列表遍历,这一步就能带来至少3倍的性能提升。

2. 避免列表遍历中删除元素,改用新列表存储存活人口

原来的p[i].pop(j)操作非常低效,直接新建一个列表存储处理后的人口即可:

new_p = []
for crowd in p[i]:
    if crowd == 1:
        if random.random() > death_chance:
            # 死亡,不加入新列表,直接减计数
            infected_cnt -=1
            alive_cnt -=1
            continue
        # 其余状态处理逻辑不变
    new_p.append(crowd)
p[i] = new_p

这一步避免了列表元素移动的开销,处理大列表时性能提升非常明显。

3. 删除无效操作,提前计算所有固定参数

  • 去掉@functools.lru_cache装饰,无参函数用缓存完全没用
  • 所有固定概率(比如reinfectation_chance、death_chance这些)初始化的时候就算好,不要每次循环重新计算
  • 初始清空文件的代码可以简化,open("results.txt", "w")默认就会清空文件内容,不需要手动seek(0)和write(""),也不需要手动调用close(),with语法会自动处理。

4. 适配PyPy的优化点

你现在用PyPy运行的话,避免不必要的字典创建和查找,你代码里的place固定是1,完全可以不用字典p,直接用一个列表就行,进一步降低开销:

# 原来的p是{1:[]},直接改成
p_list = []

省去字典的查找开销。

5. 随机数生成优化

单线程运行的场景下,可以用random.getrandbits代替部分概率判断,速度更快,比如判断大于0.5阈值的场景可以换成:

if random.getrandbits(1):
    # 对应逻辑

速度比random.random()快20%左右。

优化后性能预期

按照上面的方案修改完,在PyPy下运行速度至少可以再提升5-10倍,完全不需要切换回CPython,PyPy对这种循环密集型代码的优化效果远好于CPython。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 00:45:01