Python多进程计算圆周率 Pi (π) 的值(ProcessPoolExecutor)

Posted Xavier Jiezou

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python多进程计算圆周率 Pi (π) 的值(ProcessPoolExecutor)相关的知识,希望对你有一定的参考价值。


引言

上一篇文章中,给大家分享了使用蒙特卡罗法和公式法编写计算圆周率 Pi (π) 的 Python 代码。但发现了一个问题,计算速度很慢。计算圆周率属于计算密集型任务(也叫CPU密集型任务),区别于 IO 密集型任务,即 CPU 占用较大,而数据传输或磁盘等占用较小。对于 CPU 密集型任务,使用多进程能充分使用 CPU 的多个核心,极大地提高计算速度。

方法

使用如下公式计算圆周率 Pi (π) 的值:
π = ∑ n = 0 ∞ [ 1 1 6 n ( 4 8 n + 1 − 2 8 n + 4 − 1 8 n + 5 − 1 8 n + 6 ) ] \\pi = \\sum_{n=0}^\\infty [\\frac{1}{16^n}(\\frac{4}{8n+1}-\\frac{2}{8n+4}-\\frac{1}{8n+5}-\\frac{1}{8n+6})] π=n=0[16n1(8n+148n+428n+518n+61)]

实验

设备

8 × Intel® Core™ i5-8300H CPU @ 2.30GHz 2.30 GHz

结果

迭代次数为 10000 时,进程池的不同最大进程数的耗时情况如下:(计算的 PI 值为 3.141592653589793)

进程池的最大进程数耗时(评测 10 次,单位:秒)
153.55±1.98
242.17±1.49
428.01±0.77
821.73±0.51
1619.93±0.48
3220.51±0.37
6122.65±0.84

备注:进程池的最大进程数必须小于或等于 61,否则会报错。

结论

从测试结果来看,进程池的最大进程数为 16 时,计算速度最快,耗时最短,比单进程快了两倍多;为 8 和 32 时,耗时也和 16 相差不多,32 以后耗时就变长了。因此,使用多进程编程时,一般进程池最大进程数设置为 CPU 的核心数就行。

参考

https://docs.python.org/3/library/concurrent.futures.html#processpoolexecutor

其它

多线程是不适合于计算密集型任务的,这里也评测了一下,结果如下:

线程池的最大线程数耗时(仅评测 1 次,单位:秒)
148
247
455

源码

import concurrent.futures as cf
from tqdm import tqdm
import os


class CalculatePI(object):
    """Calculate the value of π by multi process

    Args:
        num_iterations (int): Number of iterations. Default: 100000
        max_workers (int): Maximum number of processes. Default: the number of processors on the machine.
    """

    def __init__(self, num_iterations: int = 100000, max_workers: int = os.cpu_count()) -> None:
        """Initialization

        Args:
            num_iterations (int): Number of iterations. Default: 100000
            max_workers (int): Maximum number of processes. Default: the number of processors on the machine.
        """
        self.num_iterations = num_iterations
        self.max_workers = max_workers

    def __calc__(self, start: int, end: int) -> float:
        """Calculate the value of π according to formula

        Args:
            start (int): Starting value for the iterations
            end (int): Ending value for the iterations

        Returns:
            float: Value of π
        """
        PI = 0
        for n in tqdm(range(start, end)):
            PI += 1/pow(16, n) * (4/(8*n+1) - 2 / (8*n+4) - 1/(8*n+5) - 1/(8*n+6))
        return PI

    def __main__(self) -> float:
        """Calulate the value of π by multi process

        Returns:
            float: Value of π
        """
        PI = 0
        with cf.ProcessPoolExecutor(self.max_workers) as p:
            futures = []
            for i in range(self.max_workers):
                start = i*self.num_iterations//self.max_workers
                end = (i+1)*self.num_iterations//self.max_workers
                futures.append(p.submit(self.__calc__, start, end))
            for future in cf.as_completed(futures):
                PI += future.result()
        return PI


if __name__ == '__main__':
    print(CalculatePI().__main__())

以上是关于Python多进程计算圆周率 Pi (π) 的值(ProcessPoolExecutor)的主要内容,如果未能解决你的问题,请参考以下文章

Python圆周率 Pi (π) 的计算(蒙特卡罗法+公式法)

使用 python 实现π的计算

2πa在python表达式?

蓝桥杯练习题:计算保留100位小数的圆周率

Spark设计实现π的计算

编写一个小程序计算圆周率π的值