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

Sublime Text运行Python代码遇卡顿及math domain error问题求助

解决Simpson法则串行/并行对比代码的报错与卡顿问题

问题分析

1. ValueError: math domain error 原因

报错触发于math.acos()函数,该函数要求参数必须在**[-1, 1]**范围内,原代码的核心问题有两个:

  • 多进程全局变量同步失效:g函数依赖全局变量h,但multiprocessing.Pool创建的子进程会复制主进程初始内存空间,后续主进程循环中更新的h值无法同步到子进程,导致g函数始终使用初始值h=π/2,计算出的x值远超积分区间[0, π/2],使得math.cos(x)/(1+2*math.cos(x))的绝对值可能大于1,触发定义域错误。
  • 浮点计算边界风险:即使x在合法区间,极端情况下的浮点误差也可能导致表达式结果轻微超出[-1,1]范围。

2. 构建卡顿原因

原循环中i的范围是1到9,当i=9时n=10^9,串行部分需要执行5亿次循环,计算量远超常规设备承载能力,必然导致卡顿甚至无响应。

修复后的代码

import math
import numpy as np
import time
import multiprocessing as mp
import matplotlib.pyplot as plt
from functools import partial

def f(x):
    y = math.cos(x)
    val = y / (1 + 2 * y)
    # 钳位处理,确保参数在acos合法范围内
    val = max(min(val, 1.0), -1.0)
    return math.acos(val)

b = math.pi / 2
a = 0
exact = math.pi ** 2 / 16

# 改写g函数,通过参数传递h,避免全局变量依赖
def g(j, h):
    return (f(a + (2 * j - 2) * h) + 4 * f(a + (2 * j - 1) * h) + f(a + (2 * j) * h))

if __name__ == '__main__':
    mp.freeze_support()  # Windows系统必需

    # 缩小循环范围,避免计算量过大
    max_power = 6
    serial_times = []
    parallel_times = []
    intervals = []

    # 每次循环重新创建进程池(或用starmap传递多参数)
    for i in range(1, max_power + 1):
        n = 10 ** i
        h = (b - a) / n
        N = int(n / 2)
        intervals.append(N)
    
        # 并行计算:用partial绑定h参数
        with mp.Pool(processes=mp.cpu_count()) as pool:
            start_time = time.time()
            g_with_h = partial(g, h=h)
            p = pool.map(g_with_h, np.linspace(1, N, N, dtype=np.int32))
            P = (h / 3) * np.sum(p, dtype=np.float64)
            elapsedTime = time.time() - start_time
            parallel_times.append(elapsedTime)

        # 串行计算
        start_time = time.time()
        S = 0.0
        for j in range(1, N+1):
            S += f(a + (2 * j - 2) * h) + 4 * f(a + (2 * j - 1) * h) + f(a + (2 * j) * h)
        S *= h / 3
        elapsedTime = time.time() - start_time
        serial_times.append(elapsedTime)
        print(f"完成N={N}的计算,串行耗时{elapsedTime:.4f}s,并行耗时{parallel_times[-1]:.4f}s")

    # 绘图
    plt.plot(intervals, serial_times, label='串行计算', marker='o')
    plt.plot(intervals, parallel_times, label='并行计算', marker='s')
    plt.xlabel('区间数量(N)')
    plt.ylabel('运行时间(s)')
    plt.xscale('log')
    plt.yscale('log')
    plt.title('Simpson法则计算时间 vs 区间数量')
    plt.legend()
    plt.grid(True, which="both", ls="-", alpha=0.5)
    plt.show()

关键修复点说明

  1. 移除全局变量依赖:用functools.partial将h绑定到g函数,确保子进程使用当前循环的h值,解决多进程参数同步问题。
  2. 添加钳位处理:在f函数中对表达式结果做max(min(val, 1.0), -1.0)处理,强制将参数限制在acos的合法定义域内。
  3. 控制计算规模:将循环上限从9改为6,避免极端大的计算量导致卡顿;同时添加打印语句,实时查看计算进度。
  4. 优化进程池使用:采用with语句管理进程池,确保每次循环后正确关闭进程,避免资源泄漏。

运行效果

修复后代码可正常执行,会输出每个区间数量下的串行/并行耗时,并生成对比曲线图,清晰展示并行计算在大区间数量下的时间优势。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 20:49:56