目录

Python3学习笔记(一)——多进程运算计算圆周率π


目录

我们使用公式

$$ \frac{\pi^2}{8}=\sum^\infty_{n=0}(\frac{1}{2n+1})^2=\frac{1}{1^2}+\frac{1}{3^2}+\frac{1}{5^2}+\frac{1}{7^2}+… $$

来近似计算圆周率$\pi$的值。

一般的Python写法是这样的:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
#!/usr/bin/env python3

import math, time

def pi(n):
    s = 0.0
    for i in range(n):
        s += 1/((2*i+1)**2)
    return math.sqrt(s * 8)

if __name__ == '__main__':
    ticks = time.time()
    print(pi(10000000))
    print('Time consumed: {}. '.format(time.time()-ticks))

在笔者的设备打开系统监控,然后运行上述程序,情况如图所示

https://s2.ax1x.com/2019/07/09/ZyxYjg.png

可以看到程序耗时约3.68秒,而在程序运行期间,只有一个CPU核心参与运算(见上图右侧界面中CPU History,可见只有一个CPU核心出现“高峰”)。

下面我们使用多进程进行并行运算,将pi(n)原本10000000规模的运算平均分为10份,分别交给10个进程去运算。程序如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#!/usr/bin/env python3

from multiprocessing import Pool, Queue
import os, math, time

def sub_task(left,right): #子任务,计算1/(2*left+1)^2到1/(2*right+1)的和
    print('Range ({},{}), Process {} is running... '.format(left,right,os.getpid()))
    s = 0.0
    for i in range(left,right):
        s += 1/((2*i+1)**2)
    print('Range ({},{}) done, result is {}. '.format(left,right,s))
    q.put(s) #将运算结果加入队列

def pi(n):
    unit = n / 10 #计算任务均分10份
    p = Pool() #建立进程池
    for i in range(10): #调用10个子进程
        p.apply_async(sub_task, args=(int(i*unit),int((i+1)*unit-1)))
        print('{} had been appended. '.format(i))
    print('Waiting for all processes done. ')
    p.close() #关闭进程池
    p.join() #等待进程池中的子进程全部运行完毕
    print('All processes done. ')
    s = 0.0
    while not q.empty(): #将队列中的运算结果全部相加
        s += q.get()
    return math.sqrt(8 * s)

if __name__ == '__main__':
    ticks = time.time()
    q = Queue()
    print(pi(10000000))
    print('Time consumed: {}. '.format(time.time()-ticks))

在笔者的设备打开系统监控,然后运行上述程序,情况如图所示

https://s2.ax1x.com/2019/07/09/ZyxNuQ.png

可以看到程序耗时约1.98秒,而在程序运行期间,四个CPU核心全部参与运算(见上图右侧界面中CPU History,可见四个CPU核心全部出现“高峰”)。

可见,合理使用子进程,可以充分利用计算机运算资源,提高程序的总体运行效率。