用多进程程序求e超过gmpy2的exp() - l1t1/note GitHub Wiki

import numpy as np
import gmpy2
from gmpy2 import mpfr

# 设置位数
n = 1000000 #int(input("请输入位数:"))
gmpy2.get_context().precision =int( (n+1)*3.34)

# 平方根
#result = gmpy2.sqrt(mpfr(2))
result = gmpy2.exp(mpfr(1))

# 打印结果
print("平方根结果:", str(result)[:1000002])

vs

#多线程不会快,多进程才行,至少在Linux是的
import math
import time
import sys
import gmpy2
from gmpy2 import mpz, log, const_pi
import multiprocessing
from concurrent.futures import ProcessPoolExecutor

def get_max_threads():
    """获取系统核数并限制最大线程数"""
    max_cpus = multiprocessing.cpu_count()
    return max(1, min(max_cpus, 8))  # 限制不超过8线程

def find_required_terms(digits):
    """精确计算所需最小n使得n! > 10^digits"""
    ln_10 = log(mpz(10))
    n_low, n_high = 0, 2 * (digits + 1)
    
    while n_low < n_high:
        mid = (n_low + n_high) // 2
        if mid <= 1:
            stirling = mpz(0)
        else:
            mid_mpz = mpz(mid)
            stirling = mid_mpz * log(mid_mpz) - mid_mpz + log(2 * const_pi() * mid_mpz) / 2
 
        if stirling > digits * ln_10:
            n_high = mid
        else:
            n_low = mid + 1
    
    return n_low

def calculate_part(args):
    """计算部分区间并统计耗时"""
    start, end, i = args
    part_start = time.time()
    
    coeff = numerator = mpz(1)
    for k in range(1, end-start+1):
        coeff *= (end - k + 1)
        numerator += coeff
    
    if i > 0:
        numerator -= coeff
    
    elapsed = time.time() - part_start
    return numerator, coeff, elapsed

def calculate_e_parallel(digits, num_parts=2):
    """并行分块计算(带耗时统计)"""
    m = find_required_terms(digits)
    power = mpz(10)**digits
    part_size = m // num_parts
    
    # 计算各部分区间(动态调整负载)
    ranges = []
    for i in range(num_parts):
        start = i * part_size
        end = (i+1)*part_size if i < num_parts-1 else m
        ranges.append((start, end, i))
    
    # 并行计算各部分
    max_threads = get_max_threads()
    part_times = []
    with ProcessPoolExecutor(max_workers=max_threads) as executor:
        results = list(executor.map(calculate_part, ranges))
    
    # 分离结果和耗时
    parts = []
    for numerator, coeff, elapsed in results:
        parts.append((numerator, coeff))
        part_times.append(elapsed)
    
    # 合并结果
    combined_num = 0 
    combined_den = 1 
    for num, den in reversed(parts):
        combined_num += num * combined_den
        combined_den *= den
    
    total = (combined_num * power) // combined_den
    return "2." + str(total % power), part_times


if __name__ == "__main__":
    # 测试配置
    digits = 1000000
    test_cases = [
    #    ("单线程", 1),
    #    ("2线程", 2),
    #    ("4线程", 4),
        ("8线程", 8)
    ]
    multiprocessing.freeze_support()
    print("系统核数: ", multiprocessing.cpu_count())
    print("计算e的", digits, "位近似值 (并行优化)\n")

    # 基准测试

    reference = None
    for name, parts in test_cases:
        if parts > get_max_threads():
            print(name, " 跳过(超过最大线程限制)")
            continue
            
        start = time.time()
        result, part_times = calculate_e_parallel(digits, parts)
        total_time = time.time() - start
        
        print(name, " 总耗时: ", "%.3f" % total_time, "s")
        print("各部分耗时: ", ["%.3f" % t for t in part_times], "s")
        print("前50位: ", result[:52])
        
        if reference is None:
            reference = result
        else:
            mismatch = next((i for i in range(len(reference)) if reference[i] != result[i]), None)
            print("结果验证: ", '一致' if mismatch is None else '第'+str(mismatch)+'位不一致')
        print("--------------------------------------------------")
        print(result)
        print(time.time() - start,"s")


#from multiprocessing import freeze_support

#do somthing

#if __name__ == "__main__":
#    freeze_support()  # Windows加上这一句,并要在上面一行下执行
    

测试结果

gmpy2.exp(1)
7694228188


Kernel  Time =     0.140 =   28%
User    Time =     0.375 =   77%
Process Time =     0.515 =  106%    Virtual  Memory =    509 MB
Global  Time =     0.485 =  100%    Physical Memory =     35 MB

gmpy2手工迭代+多进程
7694228188


Kernel  Time =     0.078 =   19%
User    Time =     0.140 =   35%
Process Time =     0.218 =   55%    Virtual  Memory =     19 MB
Global  Time =     0.392 =  100%    Physical Memory =     26 MB