【並行計算】經典的積分求解示例
1.前言
積分求解是講並行計算是非常常用的一個經典例子,一方面因爲其確實是一個並行運算能夠發揮更好性能的例子,另一方面也比較簡單,並不需要很深的數學基礎,下面我們就一起來看看吧!
比如下面這條y = x^2的曲線,我們想計算其在0-10這一段的積分值,當然我們可以採用求原函數的方法,但是有很多時候,當函數比較複雜時,原函數往往是求不出來的,這時,我們就可以採用數值逼近的方法,比如將其積分面積劃分爲很多個小梯形,分別求小梯形的面積,然後來求和。
而當我們需要非常高的精度時,我們一般就會將梯形劃分的很窄,梯形的數量就會非常多,可能甚至成千上萬,這取決於我們希望的精度。而這,可能是一個很耗費時間的計算過程,因爲計算是串行的,而如果我們採用並行計算的方式,將有可能以指數增加的效率來完成計算。
2. Talking is Cheap, Show me the Code!
將下面的代碼保存爲calculate_parallel.py
:
import numpy as np
import sys
from mpi4py import MPI
from mpi4py.MPI import ANY_SOURCE
comm = MPI.COMM_WORLD
rank = comm.Get_rank()
size = comm.Get_size()
integral = np.zeros(1)
receive_buff = np.zeros(1)
# get parameters from command-line
start = float(sys.argv[1])
end = float(sys.argv[2])
piece = int(sys.argv[3])
# objective function
def f(x):
return x**2
# integral calculate in a small range
def integrate_range(start, end, piece):
integral = -(f(start) + f(end))/2.0
for x in np.linspace(start, end, piece + 1):
integral += f(x)
integral = integral * (end - start)/piece
return integral
# divide the integral into pieces for processes
width = (end - start) / piece
local_piece = piece/size # pieces of a process
local_start = start + rank*local_piece*width
local_end = local_start + local_piece*width
integral[0] = integrate_range(local_start, local_end, local_piece)
# process 0 collects all results and sum
if rank == 0:
integral_sum = integral[0]
for i in range(1, size):
comm.Recv(receive_buff, ANY_SOURCE)
integral_sum += receive_buff[0]
else:
comm.Send(integral, dest=0)
if rank == 0:
print('With %d pieces, the estimation the integral of function y = x^2 from x = %f to x = %f is: %f.'
% (piece, start, end, integral_sum))
3.運行效果:
在命令行輸入:
mpiexec -n 4 python calculate_parallel.py 0 10 16
輸出爲:
(base) C:\Users\44375\Documents\python_proj>mpiexec -n 4 python calculate_parallel.py 0 10 16
With 16 pieces, the estimation the integral of function y = x^2 from x = 0.000000 to x = 10.000000 is: 333.984375.
4.該如何改進?
細心的朋友可能已經發現,上面的代碼中,實際上我們在最後求和的過程中也是串行的,這對我們提升計算速度而言是不利的,那麼有沒有其他的方案呢?
下面給出一點思路供大家參考:
通過上圖,大家可以看到在A中,也就是我們上面代碼中採用的思路,A需要串行的去加2.3.4的結果,而在B中,則將A的計算過程轉移了一部分到3中,使A僅需要進行兩次計算,這看起來僅僅少了一次,但是當進程數成百上千時,這個時間利用效率是呈指數增加的。
參考
1.Point-to-Point Communication with Python and mpi4py (lecture 4/5)