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

多线程计算圆周率(π)时输出结果随机异常问题排查

问题排查与修复

问题根源

你的代码结果随机的核心原因是线程执行顺序不确定:

  • 多个线程向全局列表io中追加计算结果的顺序完全由操作系统线程调度决定,没有固定性
  • 后续汇总时,你通过io列表的索引奇偶性来决定加减符号,这完全依赖列表元素的顺序与项的符号严格对应,但线程顺序随机导致符号匹配完全混乱,最终结果偏离π

修复思路

不要依赖线程执行顺序来判断符号,而是将每个线程计算的项对应的符号与数值绑定存储,确保汇总时符号与对应项的和一一对应,不受线程顺序影响。

莱布尼茨公式中,项的符号由分母决定:
π/4 = 1 - 1/3 + 1/5 - 1/7 + 1/9 - ...
即分母为4k+1时符号为正,4k+3时符号为负,也可以通过(-1)^((分母-1)/2)计算符号。

修复后的代码

from decimal import *
import threading
from threading import Thread as thr

getcontext().prec = 600

io = []

def ev(startingVal, rangeValue, countThread):
    global io
    # 计算当前分组项的符号
    term_index = (startingVal - 1) // 2
    sign = (-1) ** term_index
    number = Decimal(0)
    for x in range(rangeValue):
        denominator = startingVal + countThread * x
        number += Decimal(1) / denominator
    # 存储符号与对应项的和
    io.append((sign, number))

thread_count = 2 * 8  # 控制线程分组间隔,8个实际工作线程

def listThread():
    # 生成处理所有奇数分母分组的线程
    return [thr(target=ev, args=(x, 10000, thread_count)) for x in [y for y in range(thread_count) if y % 2 == 1]]

rt = listThread()
for x in rt:
    x.start()
for x in rt:
    x.join()

# 汇总时按绑定的符号计算
k = Decimal(0)
for sign, val in io:
    k += sign * val

print(k * 4)

额外优化点

  • 移除了原代码中未使用的n、num变量,精简代码
  • 去掉了原ev函数中无用的oldNum参数,每个线程独立计算对应分组的和

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 18:20:28