Python 3.8 骰子模拟项目大参数输入时随机数生成速度过慢问题咨询
骰子投掷程序运行缓慢的原因与优化方案
核心性能瓶颈
- 高频控制台I/O是最大的性能杀手:原代码每完成一次投掷就执行一次
print("Throw ", i, " of ", nt),控制台输出是系统级阻塞I/O操作,当投掷次数达到上万次时,这部分操作占用的时间会远高于计算本身的耗时,绝大多数场景下的卡顿都来源于此。 - 逐次调用随机数函数的固定开销极高:原代码对每一次投掷、每一个骰子都单独调用
random.randint(1,6),单次Python函数调用的固定开销不低,当总随机数调用次数达到数十万乃至上百万次时,光函数调用的额外开销就会消耗大量时间。 - 存在完全无意义的冗余计算:代码生成完所有投掷结果后,额外对整个结果列表做了全量排序(
sums.sort()),但后续用Counter统计频率完全不需要输入列表是有序的,这步操作在大列表上会带来不必要的O(n log n)时间开销。 - 循环结构效率极低:原代码用两层
while循环手动维护计数器c、循环变量i、累计值sum,没有利用Python内置的循环迭代能力,解释器层面的执行效率很低;同时变量名sum、max、min和Python内置函数重名,会额外增加解释器的名称查找开销。
针对性优化方案
- 调整日志打印逻辑:去掉单次投掷就打印一次进度的写法,要么完全关闭过程打印,要么每完成固定比例(比如1%)的投掷任务再输出一次进度,把高频I/O的开销降到可忽略的水平。
- 替换随机数生成逻辑:优先用NumPy的向量化随机数生成能力,一次性生成所有投掷需要的骰子结果、直接沿轴求和,整个过程在C语言层面执行,没有Python层的循环和函数调用开销,性能可以提升100~1000倍。如果不依赖NumPy,也可以把两层while循环替换为Python生成器表达式的循环结构,减少手动维护变量的开销。
- 删除冗余计算:直接移除
sums.sort()代码,统计频率、计算最大最小值都可以在无序列表上完成,不需要预先排序。 - 修正变量命名冲突:把临时变量
sum改名为total,max、min改名为res_max、res_min,避免遮蔽Python内置函数带来的性能损耗。
可参考的优化实现
高性能NumPy版本(适合大参数场景)
import numpy as np import matplotlib.pyplot as plt nd = int(input("Insert number of dice: ")) nt = int(input("Insert number of throws: ")) print(f"{nd} dice thrown {nt} times") print("Generating sums, please hold....") # 一次性生成所有骰子结果,向量化求和 all_dice = np.random.randint(1, 7, size=(nt, nd)) sums = all_dice.sum(axis=1) # 直接计算极值 res_max = sums.max() res_min = sums.min() print(f"||Maximum result: {res_max} ||Minimum result: {res_min}") # 用bincount做频率统计,比Counter速度更快 freq = np.bincount(sums) y = np.nonzero(freq)[0] x = freq[y] print("Rappresenting results") plt.plot(y, x) plt.xlabel("Risultati") plt.ylabel("Frequenza") plt.title("Distribuzione delle somme") plt.grid(True) plt.tight_layout() plt.show()
纯Python无依赖版本(优化后比原代码快3~5倍)
import random from collections import Counter import matplotlib.pyplot as plt nd = int(input("Insert number of dice: ")) nt = int(input("Insert number of throws: ")) print(f"{nd} dice thrown {nt} times") print("Generating sums, please hold....") sums = [sum(random.randint(1,6) for _ in range(nd)) for _ in range(nt)] res_max = max(sums) res_min = min(sums) print(f"||Maximum result: {res_max} ||Minimum result: {res_min}") freq_counter = Counter(sums) y = list(freq_counter.keys()) x = list(freq_counter.values()) print("Rappresenting results") plt.plot(y, x) plt.xlabel("Risultati") plt.ylabel("Frequenza") plt.title("Distribuzione delle somme") plt.grid(True) plt.tight_layout() plt.show()
内容的提问来源于stack exchange,提问作者Mario Scuderi
相关产品推荐
相关产品推荐

