二、MPI與mpi4py
MPI是Message Passing Interface的簡(jiǎn)稱,也就是消息傳遞。消息傳遞指的是并行執(zhí)行的各個(gè)進(jìn)程具有自己獨(dú)立的堆棧和代碼段,作為互不相關(guān)的多個(gè)程序獨(dú)立執(zhí)行,進(jìn)程之間的信息交互完全通過顯示地調(diào)用通信函數(shù)來完成。
Mpi4py是構(gòu)建在mpi之上的python庫(kù),使得python的數(shù)據(jù)結(jié)構(gòu)可以在進(jìn)程(或者多個(gè)cpu)之間進(jìn)行傳遞。
2.1、MPI的工作方式很簡(jiǎn)單,就是你啟動(dòng)了一組MPI進(jìn)程,每個(gè)進(jìn)程都是執(zhí)行同樣的代碼!然后每個(gè)進(jìn)程都有一個(gè)ID,也就是rank來標(biāo)記我是誰。什么意思呢?假設(shè)一個(gè)CPU是你請(qǐng)的一個(gè)工人,共有10個(gè)工人。你有100塊磚頭要搬,然后很公平,讓每個(gè)工人搬10塊。這時(shí)候,你把任務(wù)寫到一個(gè)任務(wù)卡里面,讓10個(gè)工人都執(zhí)行這個(gè)任務(wù)卡中的任務(wù),也就是搬磚!這個(gè)任務(wù)卡中的“搬磚”就是你寫的代碼。然后10個(gè)CPU執(zhí)行同一段代碼。需要注意的是,代碼里面的所有變量都是每個(gè)進(jìn)程獨(dú)有的,雖然名字相同。
例如,一個(gè)腳本test.py,里面包含以下代碼:
1 2 | [color=rgb(248, 248, 242) !important]from mpi4py import [color=rgb(249, 38, 80) !important]MPIprint([color=rgb(230, 219, 93) !important]"hello world'') [color=rgb(230, 219, 93) !important]print("my rank [color=rgb(102, 217, 239) !important]is: %d" %MPI.rank) |
然后我們?cè)诿钚型ㄟ^以下方式運(yùn)行:
#mpirun –np 5 python test.py
-np5 指定啟動(dòng)5個(gè)mpi進(jìn)程來執(zhí)行后面的程序。相當(dāng)于對(duì)腳本拷貝了5份,每個(gè)進(jìn)程運(yùn)行一份,互不干擾。在運(yùn)行的時(shí)候代碼里面唯一的不同,就是各自的rank也就是ID不一樣。所以這個(gè)代碼就會(huì)打印5個(gè)hello world和5個(gè)不同的rank值,從0到4.
2.2、點(diǎn)對(duì)點(diǎn)通信點(diǎn)對(duì)點(diǎn)通信(Point-to-PointCommunication)的能力是信息傳遞系統(tǒng)最基本的要求。意思就是讓兩個(gè)進(jìn)程直接可以傳輸數(shù)據(jù),也就是一個(gè)發(fā)送數(shù)據(jù),另一個(gè)接收數(shù)據(jù)。接口就兩個(gè),send和recv,來個(gè)例子:
1 2 3 4 5 6 7 | [color=rgb(248, 248, 242) !important]import mpi4py.MPI [color=rgb(102, 217, 239) !important]as MPI comm = MPI.[color=rgb(249, 38, 80) !important]COMM_WORLD comm_rank = comm.[color=rgb(249, 38, 80) !important]Get_rank() comm_size = comm.[color=rgb(249, 38, 80) !important]Get_size() [color=rgb(184, 92, 0) !important]# point to point communicationdata_send = [comm_rank]*5comm.send(data_send,dest=(comm_rank+1)%comm_size) data_recv =comm.[color=rgb(249, 38, 80) !important]recv(source=(comm_rank-[color=rgb(174, 129, 255) !important]1)%comm_size)[color=rgb(249, 38, 80) !important]print([color=rgb(230, 219, 93) !important]"my rank is %d, and Ireceived:" % comm_rank)print data_recv |
啟動(dòng)5個(gè)進(jìn)程運(yùn)行以上代碼,結(jié)果如下:
1 2 3 4 5 6 7 8 9 10 | [color=rgb(248, 248, 242) !important]my rank [color=rgb(102, 217, 239) !important]is [color=rgb(174, 129, 255) !important]0, [color=rgb(102, 217, 239) !important]and I received: [[color=rgb(174, 129, 255) !important]4, [color=rgb(174, 129, 255) !important]4, [color=rgb(174, 129, 255) !important]4, [color=rgb(174, 129, 255) !important]4, [color=rgb(174, 129, 255) !important]4 my rank [color=rgb(102, 217, 239) !important]is [color=rgb(174, 129, 255) !important]1, [color=rgb(102, 217, 239) !important]and I received: [[color=rgb(174, 129, 255) !important]0, [color=rgb(174, 129, 255) !important]0, [color=rgb(174, 129, 255) !important]0, [color=rgb(174, 129, 255) !important]0, [color=rgb(174, 129, 255) !important]0 my rank [color=rgb(102, 217, 239) !important]is [color=rgb(174, 129, 255) !important]2, [color=rgb(102, 217, 239) !important]and I received: [[color=rgb(174, 129, 255) !important]1, [color=rgb(174, 129, 255) !important]1, [color=rgb(174, 129, 255) !important]1, [color=rgb(174, 129, 255) !important]1, [color=rgb(174, 129, 255) !important]1 my rank [color=rgb(102, 217, 239) !important]is [color=rgb(174, 129, 255) !important]3, [color=rgb(102, 217, 239) !important]and I received: [[color=rgb(174, 129, 255) !important]2, [color=rgb(174, 129, 255) !important]2, [color=rgb(174, 129, 255) !important]2, [color=rgb(174, 129, 255) !important]2, [color=rgb(174, 129, 255) !important]2 my rank [color=rgb(102, 217, 239) !important]is [color=rgb(174, 129, 255) !important]4, [color=rgb(102, 217, 239) !important]and I received: [[color=rgb(174, 129, 255) !important]3, [color=rgb(174, 129, 255) !important]3, [color=rgb(174, 129, 255) !important]3, [color=rgb(174, 129, 255) !important]3, [color=rgb(174, 129, 255) !important]3 |
可以看到,每個(gè)進(jìn)程都創(chuàng)建了一個(gè)數(shù)組,然后把它傳遞給下一個(gè)進(jìn)程,最后的那個(gè)進(jìn)程傳遞給第一個(gè)進(jìn)程。comm_size就是mpi的進(jìn)程個(gè)數(shù),也就是-np指定的那個(gè)數(shù)。MPI.COMM_WORLD 表示進(jìn)程所在的通信組。
但這里面有個(gè)需要注意的問題,如果我們要發(fā)送的數(shù)據(jù)比較小的話,mpi會(huì)緩存我們的數(shù)據(jù),也就是說執(zhí)行到send這個(gè)代碼的時(shí)候,會(huì)緩存被send的數(shù)據(jù),然后繼續(xù)執(zhí)行后面的指令,而不會(huì)等待對(duì)方進(jìn)程執(zhí)行recv指令接收完這個(gè)數(shù)據(jù)。但是,如果要發(fā)送的數(shù)據(jù)很大,那么進(jìn)程就是掛起等待,直到接收進(jìn)程執(zhí)行了recv指令接收了這個(gè)數(shù)據(jù),進(jìn)程才繼續(xù)往下執(zhí)行。所以上述的代碼發(fā)送[rank]*5沒啥問題,如果發(fā)送[rank]*500程序就會(huì)半死不活的樣子了。因?yàn)樗械倪M(jìn)程都會(huì)卡在發(fā)送這條指令,等待下一個(gè)進(jìn)程發(fā)起接收的這個(gè)指令,但是進(jìn)程是執(zhí)行完發(fā)送的指令才能執(zhí)行接收的指令,這就和死鎖差不多了。所以一般,我們將其修改成以下的方式:
1 2 3 4 5 | [color=rgb(248, 248, 242) !important] |
原文 http://blog.csdn.net/zouxy09/article/details/49031845
轉(zhuǎn)載請(qǐng)注明:綠安網(wǎng) » Python多核編程mpi4py實(shí)踐