MPI 分布内存并行 程序开发. 第四章 点对点通信函数 第四章 点对点通信函数 传送机制(两种): 阻塞方式,它必须等到消息从本地送出之后才可 以执行后续的语句,保证了缓冲区等资源的可再 用性; 非阻塞方式,它不须等到消息从本地送出就可以 执行后续的语句,但非阻塞调用的返回并不保证 资源的可再用性。

Slides:



Advertisements
Liknende presentasjoner
1 Pointere, referencer, struct’s mv.. 2 Erklæringer Eksempel på erklæringer int i, *ip, f ( ), *fip( ), (*pfi) ( ); Erklærer en integer, en pointer til.
Advertisements

 練習 XSL 程式的撰寫 › 了解 XSL 的轉換意義  在 XML 文件中宣告 XSL › fhwang XML Programming 10.
6218 白盛弘. 北極熊的家 8&p=%E5%8C%97%E6%A5%B5%E7%86%8A&fr2=tab-web&fr=yfp-s.
鼾音訊號測量計畫 執導老師 : 侯春茹 老師 組員 : 金雍庭 胡庭恩 林承葦 賴彥亨. 目錄 訊號的簡介 ▫ 臨床應用 ▫ 量測部位與方法 ▫ 訊號特徵 訊號處理流程 鼾聲量得訊號.
いまこれが熱い 米国の Web2.0 サービス CNET Japan Innovation Conference 2006 Autumn データセクション(株) 橋本大也 (株)ネットエイジグループ チーフエバンジェリスト.
LHU_ME 魏慶隆 李瑞宗老師 零件組立之基本操作  零件組立之步驟  Component  Assembly  [ 選取零件 ]  定位  定位指令說明 定位指令說明.
2009 Summer Camp MRP 物料需求規劃 演講者:黃怡勳.
是 1. 全球暖化是真的嗎 ? 人類 2. 是什麼原因又是誰造成的 ? 破壞基本生態的穩定 3. 氣候改變對地球及我們有什麼影響 ? 最貧窮、最低窪、最熱的國家受害最大,但是每個人都無法倖免 於難 4. 誰會受到最大的衝擊 ? 發展與氣候變化 國際商務學系 A 林宜 如.
弊社取り扱いスマートホン媒 体 Avarice Yell inc.. スマートフォン取り扱い アドネットワーク&リスティング Avarice Yell inc.
線形代数学.
Order To Cash 主講人:蓋冠宇.
芬蘭 - 進口 黃硯翎 A 國花:鈴蘭. 芬蘭進口 黃硯翎 A 國家印象代表圖 ~~ 桑拿浴.
要求プロセスの数量化 要求工学 WG in 宇和島 要求獲得 要求記述 要求検証 要求管理 Stakeholder の識別 要求抽出 ネゴシエーション モデル化 記述 記述の解析 テスト・実行 要求工学プロセス.
人类进步与环境代价 —— 绿色化学关注的问题 孙立广 (中国科技大学极地环境研究室). 一、引言 从绿色革命到绿色科技 20 世纪 60 年代 “ 绿色革命 ” 的结果: 农作物高产 高产水稻品种 化肥大量使用烈性农药 水土污染、 肥力降低 水荒.
小沢研究室紹介 大学院を志す人のために. 素粒子・原子核物理学とは? 自然を支配する基本法則はどのようなものか 物質を構成する究極の要素は何か 宇宙はなぜ現在の姿になっているのか 宇宙にはどのような物質が存在し、それはどのように作られ たのか 2000年以上も前から人類の探究心を駆り立ててやまないこれら.
第 14 章 SQL 語言處理資料庫 14-1 SQL 語言的基礎14-1 SQL 語言的基礎 14-2 SQL 資料庫查詢指令14-2 SQL 資料庫查詢指令 14-3 SQL 聚合函數14-3 SQL 聚合函數 14-5 SQL 語言的資料庫操作14-5 SQL 語言的資料庫操作.
HTML + Dreamweaver 學術 課程. 甚麼是 HTML ? HTML 全名是 Hyper Text Markup Language ﹐ 是電腦語言的一種。這種電腦語言是可透過瀏 覽軟件 (Browser - Internet Explorer, Netscape) 翻譯出來﹐翻出來的就是我們看到的.
1 © 2011 台灣培生教育出版 (Pearson Education Taiwan). 2 學習目標 1. 了解收益管理在供應鏈中所扮演的角色。 2. 界定出何種收益管理做法具有效率的情況。 3. 描述制定收益管理決策時,需要考量的取捨條 件。
雜 湊 表.
中国法律检索系统. 数据库介绍 系统收录 22 个相对独立但又互通互联的法律信息数据库:《中 国法律法规规章司法解释全库》、《中国地方法规规章库》、 《港澳台法律库》、《中华人民共和国条约库》、《外国与国际 法律库》、《法律文书样式库》、《最高人民法院公报案例库》、 《中国法院裁判文书数据库》、《合同范本数据库》、《仲裁裁.
1 Understanding and Constructing Approaches to Teaching 第二講 教案設計初探 林碧霞博士 Lam Bick Har©2006.
2005 年 1 月 18 日台灣視障用數位典藏之 語音檢索系統 1 「貓頭鷹」 ~ 台灣視障用數位典藏 之語音檢索系統 93 年數位典藏創意加值計畫心得交流 「貓頭鷹」 ~ 台灣視障用數位典藏 之語音檢索系統 93 年數位典藏創意加值計畫心得交流 報告人 : 唐傳義 張智星 國立清華大學資工系教授.
EQ與情緒管理 資料截自清涼音出版社(VCD AV13)-張錦貴教授.
计算器的使用 CASIO 系列. 可编程序计算器使用方法简介 CASIO fx-350ms.
2009 年世界地球日 您必須知道的全球暖化現況 為倡導保護地球,國際上訂定每年的四月二十四 日世界地球日。今年活動主軸是大家一齊來防止地 球暖化。在那一天,世界各地愛護環境的人,不但 要用行動展現「熱愛地球」實力,也要依推動者的 建議,一齊穿上藍色系列的衣裝出門,以展現退暖.
第八組  M 林秋香 M 顧家容  M 裴方南 M 陳黃慶璃  M 賴盈如 M 葉芳如.
A02 通識教育課程 ( 二年級 ) 生物化學、醫學生涯、醫學研究方法 金髮小蜜的故事 教案代碼: 9622A02-4.
企業員工訓練與發展 7.1 訓練與發展的意義與系統化程序 7.2 訓練需求分析 7.3 訓練的設計與準備 7.4 非管理職員工的訓練方法
Word Word 2000 的操作環境 功能表列 尺規 垂直捲軸 顯示模式 瀏覽物件鈕 水平捲軸 狀態顯示列 內文區域 關閉鈕 放到最大鈕 縮到最小鈕標題列 插入點.
專業‧互相尊重‧開拓者精神 台北大學投影機案 教 育 訓 練. Agenda § 使用前注意說明 § 控制面板操作說明 § 投影布幕之使用 § 關機操作順序說明 § 簡易故障排除 § 問題討論時間.
教學助理培訓課程 部落格城市管理 講師 : 程如晞.
土地使用管制 2008 年 10 月 23 日. 政府導向 社會目標 比較真實市場 與社會目標 規劃 政策 政府 市場 失靈 土地市場 財產市場 傳統福利經濟學觀點下的規劃理念 設計 引起被發現 去改變.
講述教學法案例.
11 類別化程式 11.1 結構與類別 結構與類別 結構化程式設計 結構化程式設計 物件導向程式設計 物件導向程式設計 程式類別 (class)
1987 年的 聖誕節前夕,當我正在美國進修 資管碩士學位時,有一門課要求我們四個 人一組到企業去實際幫他們寫系統,由於 同組的另外三個老美對系統開發都沒什麼 概念,所 以我這位組長只好重責一肩挑起, 幾乎是獨立完成了所有的工作。終於拖到 了結案,廠商及老師對我們的(其實是我 的)系統都相當滿意。第二天我滿懷希望.
類比式語言教室材使用說明會 東吳大學語言教學中心. 說明會內容 l 開(關)機步驟 l 操作畫面說明:聲音頻道、影像頻道 l 操作示範: DVD 影片、教學電腦、錄影 帶、 3D 教材提示機、錄音帶 l 耳機互動:監聽、對話、分組、示範 l 錄音功能:對拷、學生自主拷貝.
4.1 單向鏈結串列 4.2 堆疊的加入與刪除 4.3 佇列的加入與刪除 4.4 其他型式的佇列
香港科技大学学生会 语言学会 广东话课程 2007 第二节 自我介绍. 温习 1 早晨 返学 放学 jou2 san4 faan1 hok6 fong3 hok6 你上几点堂? nei3 seung5 gei2 dim2 tong4 你食左早餐未呀? nei5 sik6 jo2 jou2 can1.
江西省委组织部远教办 (地 市 视 频 会 议 系 统)培训 江西省委组织部远教办 (地 市 视 频 会 议 系 统)培训 主讲人:饶斌.
口腔良性腫瘤 蔡政峰醫師.
加藤ゼミへのエントリー (ゼミ活動の際のスタッフプレート ♪ ). エントリーシート方式 面談 2〜3名で、 10 〜 20 分の面談をします。 エントリーシート を提出してもらいます。
民意型態 民意調查 蔡佳泓.  True Believers— 真實信仰者,具有意識形態  Concerned Citizen— 關心政治者,對於政治 有興趣.
國立台北科技大學 工業工程與管理所碩士論文 網頁行銷美學與顧客體驗關鍵因素之研究 指導教授:羅啟源教授 研究生:黃金圳甄
克里斯提安.齊瑪曼 (Krystian Zimerman) 齊瑪曼  出生於波蘭扎布熱  父親啟蒙開始學習鋼琴  1963 年在卡托維治音樂院師從 楊辛斯基 楊辛斯基  1975 年贏得蕭邦國際 鋼琴大賽第一名,當時年僅十九歲 鋼琴大賽第一名,當時年僅十九歲.
林綺雲 國立台北護理學院 生死教育與輔導研究所教授(創所所長)
資料結構 7-1 陣列 7-2 鏈結串列 7-3 堆疊和佇列 7-4 樹狀結構.
財務管理概論 劉亞秋‧薛立言 合著 (東華書局, 2007)
行銷學 marketing: an introduction
授課老師:吳有龍 教授 報告學生:王智鳳 學號: G 優使性 - 需求分析及高階設計 優使性 - 需求分析及高階設計.
嵌入式操作系统 陈香兰 助教:毛熠璐、吴昊 Spring 2008.
報告人:李克強 校內分機: : 圖書館電子資源利用講習.
台北大學統計系 汪群超 資料庫系統 汪群超02/22/2000. 資料庫資訊系統實例 貿易訂單管理 貿易訂單管理 職棒球員攻守紀錄 職棒球員攻守紀錄 圖書資訊系統 圖書資訊系統 VCD/DVD 租借管理系統VCD/DVD 租借管理系統 網路商場 網路商場.
吉林大学远程教育 共 计: 48 学时 主讲单位: 吉林大学基础医学院 药 理 教 研 室 第 二 十 七 讲 主讲教师: 李 晶.
第二节 鞭毛菌亚门真菌(Mastigomycotina)
1 《通信原理》总结 2 通信原理是通信学科的理论基础, 以调制和编码技术为核心,着重介绍 传输信号的形成和接收方式,进行理 论分析与性能评价。 可靠性 模拟系统的噪声性能分析 数字系统的误码性能分析 差错控制编码 有效性 各种信道复用方式: TDM , FDM , CDMA 等。
UClinux 简介 Embedded operating system μClinux uClinux 是应用于嵌入式设备的最著名、应用 最广泛一个 Linux 发行版本,它也是一个开放 源码的项目, uClinux 的源代码和开发工具可 以免费从
偵錯技術.
-- Homo Sapien -- DESIGN For A Especial Spirit Group : b 陳姵華 b 蘇若 喬 b 王淑燕 b 柳柏亙.
第 13 章 檔案與資料夾處理 13-1 檔案與資料夾操作 13-1 檔案與資料夾操作 13-2 循序檔案的文字檔案讀寫 13-2 循序檔案的文字檔案讀寫 13-3 隨機檔案的處理 13-3 隨機檔案的處理 13-4 二進位檔案的讀寫 13-4 二進位檔案的讀寫 13-5 檔案對話方塊 13-5 檔案對話方塊.
CorelDRAW X4 平面设计半月通 ─ 电子教案 第二章 手绘和形状工具的使用 本章导读 本章要点本章任务 上机实训.
DESIGNER. 創作主題: FANTASY 幻想旅程 報名方式:傳真報名 ─ 報名 ─ ( 報名表請向系辦索取或至「校園比賽 Facebook 粉絲團」下載 ) 競賽組隊:分為大專組與高中職組 報名隊伍以個人或團體組隊參加皆可,每人以報名一組為限.
有机化学 主讲教师 霍文兰 教 材 高鸿宾 主编. Chapter 5 alkynes alkadiene.
第六章 纱线和织物的基本知识.
2015 年学员操作手册 奥鹏教育. C o nt en ts 目录目录 平台首页简介 1 个人工作室 2 学习任务 3 研修活动 4 坊内答疑 5 资源分享 6.
现代陶艺 现代陶艺 -- 泥条盘筑成型 -- 泥条盘筑成型 任课教师 赵 芳. 一、陶艺的概念 所谓陶艺,它泛指陶瓷日用品,陈设品的造型、釉色 和装饰等所呈现的艺术特点,也专指陶器之中的艺术陶器 和瓷器中的艺术瓷。 陶艺作品是典型的工艺美术,它既有其他工艺美术的 共性,更有着区别于其他工艺美术的质的规定性。任何一.
野生动物保护系列讲座. 我们中国人自称为龙的传人。清朝 光绪年代,总税务司发行 “ 大龙邮票 ” , 大龙邮票的最早发行日期被认为在 1878 年 7 月 24 日至 8 月 1 日之间。 龙文化 —— 龙年.
3dsmax 基本工具介绍 3dsmax 基础建模类型介绍 多边形建模操作技巧 材质基础知识介绍 讲授: 8 节 实训: 8 节 掌握游戏 3D 制作工具 —3dsmax 的基本工作原理。
XXX 交流电路的功率. 一、正弦交流电路功率的基本概念 设正弦交流电路的总电压 u 与总电流 i 的相位差 ( 即阻 抗角 ) 为  ,则电压与电流的瞬时值表达式为 u = U m sin(  t   ) , i = I m sin(  t) 瞬时功率为 p = ui = U m I m.
Utskrift av presentasjonen:

MPI 分布内存并行 程序开发

第四章 点对点通信函数 第四章 点对点通信函数 传送机制(两种): 阻塞方式,它必须等到消息从本地送出之后才可 以执行后续的语句,保证了缓冲区等资源的可再 用性; 非阻塞方式,它不须等到消息从本地送出就可以 执行后续的语句,但非阻塞调用的返回并不保证 资源的可再用性。

 阻塞通信正确返回后,其后果是: - 该调用要求的通信操作已正确完成 - 该调用要求的通信操作已正确完成 - 该调用的缓冲区可用 - 该调用的缓冲区可用  消息信封要匹配  接收到的消息是最早发送的  非阻塞通信主要用于计算和通信的重叠, 从而提高整个程序执行的效率。

MPI 点对点通信函数的参数格式一般如下所示: MPI 消息传递函数参数

请求( request ) 请求( request )  这个参数用于非阻塞发送和非阻塞接收操作。 由于非阻塞操作返回后,数据可能继续存在缓 冲中,由此需要一种机制来检测资源是否可用。 根据该变量调用其它函数完成消息的实际发送 和接收。在 C 程序中,这个参数是指向 MPI_Request 结构的指针。

通讯模式( 4 种):  标准通信模式 (MPI_SEND)  缓存通信模式 (MPI_BSEND)  同步通信模式 (MPI_SSEND)  就绪通信模式 (MPI_RSEND)

 标准( standard )模式:对数据的缓冲由 具体 MPI 实现决定,与用户程序无关; 发送操作的正确返回而不要求接收操作收 到发送的数据。 发送操作的正确返回而不要求接收操作收 到发送的数据。 SR 1

 缓冲区( buffered )模式:用户定义,使用 和回收缓冲区,不管接收操作是否启动, 发送操作都可以执行,但是必须保证缓冲 区可用。 SR 1 缓冲区 2

u 同步 (synchronous) 模式:开始不依赖于 接收进程相应的操作是否启动,但必须 等到接受开始启动发送才可以返回 SR

u 就绪 (ready) 模式:只有当接收操作已经 启动时,才可以在发送进程启动发送操 作,否则发送将出错。 SR 1212

例 3 、死锁的发送接收序列 例 3 、死锁的发送接收序列 CALL MPI_COMM_RANK(comm,rank,ierr) CALL MPI_COMM_RANK(comm,rank,ierr) IF (rank.EQ.0) THEN IF (rank.EQ.0) THEN CALL MPI_RECV(recvbuf,count,MPI_REAL,1, CALL MPI_RECV(recvbuf,count,MPI_REAL,1, tag,comm,status,ierr) tag,comm,status,ierr) CALL MPI_SEND(sendbuf,count,MPI_REAL,1, CALL MPI_SEND(sendbuf,count,MPI_REAL,1, tag,comm,ierr) tag,comm,ierr) ELSE IF (rank.EQ.1) ELSE IF (rank.EQ.1) CALL MPI_RECV(recvbuf,count,MPI_REAL,0, CALL MPI_RECV(recvbuf,count,MPI_REAL,0, tag,comm,status,ierr) tag,comm,status,ierr) CALL MPI_SEND(sendbuf,count,MPI_REAL,0, CALL MPI_SEND(sendbuf,count,MPI_REAL,0, tag,comm,ierr) tag,comm,ierr) ENDIF ENDIF

进程 0 进程 1 从进程 1 接收消息 A 向进程 1 发送消息 C 从进程 0 接收消息 B 向进程 0 发送消息 D A B C D

例 4 、不安全的发送接收序列 例 4 、不安全的发送接收序列 CALL MPI_COMM_RANK(comm,rank,ierr) IF (rank.EQ.0) THEN IF (rank.EQ.0) THEN CALL MPI_SEND(sendbuf,count,MPI_REAL,1, CALL MPI_SEND(sendbuf,count,MPI_REAL,1, tag,comm,ierr) tag,comm,ierr) CALL MPI_RECV(recvbuf,count,MPI_REAL,1, CALL MPI_RECV(recvbuf,count,MPI_REAL,1, tag,comm,status,ierr) tag,comm,status,ierr) ELSE IF (rank.EQ.1) ELSE IF (rank.EQ.1) CALL MPI_SEND(sendbuf,count,MPI_REAL,0, CALL MPI_SEND(sendbuf,count,MPI_REAL,0, tag,comm,ierr) tag,comm,ierr) CALL MPI_RECV(recvbuf,count,MPI_REAL,0, CALL MPI_RECV(recvbuf,count,MPI_REAL,0, tag,comm,status,ierr) tag,comm,status,ierr) ENDIF ENDIF

进程 0 进程 1 从进程 1 发送消息 A 向进程 1 接收消息 C 从进程 0 发送消息 B 向进程 0 接收消息 D A B C D 系统缓冲区

程序 5 、安全的发送接收序列 程序 5 、安全的发送接收序列 CALL MPI_COMM_RANK(comm,rank,ierr) IF (rank.EQ.0) THEN IF (rank.EQ.0) THEN CALL MPI_SEND(sendbuf,count,MPI_REAL,1, CALL MPI_SEND(sendbuf,count,MPI_REAL,1, tag,comm,ierr) tag,comm,ierr) CALL MPI_RECV(recvbuf,count,MPI_REAL,1, CALL MPI_RECV(recvbuf,count,MPI_REAL,1, tag,comm,status,ierr) tag,comm,status,ierr) ELSE IF (rank.EQ.1) ELSE IF (rank.EQ.1) CALL MPI_RECV(recvbuf,count,MPI_REAL,0, CALL MPI_RECV(recvbuf,count,MPI_REAL,0, tag,comm,status,ierr) tag,comm,status,ierr) CALL MPI_SEND(sendbuf,count,MPI_REAL,0, CALL MPI_SEND(sendbuf,count,MPI_REAL,0, tag,comm,ierr) tag,comm,ierr) ENDIF ENDIF

进程 0 进程 1 从进程 1 发送消息 A 向进程 1 接收消息 C 从进程 0 接收消息 B 向进程 0 发送消息 D A B C D

例子 6 例子 6  clock=(myrank+1)%groupsize;  anticlock=(myrank+groupsize-1)%groupsize;  MPI_Send(buf1,LENGTH,MPI_CHAR,clock,tag,MPI_COM M_WORLD);  MPI_Recv(buf2,LENGTH,MPI_CHAR,anticlock,tag,MPI_C OMM_WORLD,&status); 012

改进: 改进:  MPI_Isend(buf1,LENGTH,MPI_CHAR,clock,tag,MPI_COMM_WORLD,&req uest);  MPI_Recv(buf2,LENGTH,MPI_CHAR,anticlock,tag,MPI_COMM_WORLD,& status);  MPI_Wait(&request,&status);  ---------------------------------  MPI_Irecv(buf2,LENGTH,MPI_CHAR,anticlock,tag,MPI_COMM_WORLD,&r equest);  MPI_Send(buf2,LENGTH,MPI_CHAR,clock,tag,MPI_COMM_WORLD);  MPI_Wait(&request,&status);

第五章 集合通信函数 l 集合通信是包含在通信因子中的所有进程都 参加操作。 l 集合通信一般实现三个功能 通信:组内数据的传输 通信:组内数据的传输 同步:组内所有进程在特定的地点在执行 同步:组内所有进程在特定的地点在执行 进度上取得一致 进度上取得一致 计算:对给定的数据完成一定的操作 计算:对给定的数据完成一定的操作

集合操作的三种类型: 集合操作的三种类型:  同步 (barrier) :集合中所有进程都到达 后,每个进程再接着运行;  数据传递:广播 (broadcast) 、分散 (scatter) 、收集 (gather) 、全部到全部 (alltoall) ;  规约 (reduction) :集合中的其中一个进 程收集所有进程的数据并计算(如:求 最大值、求最小值、加、乘等);

集合通信函数 集合通信函数  MPI_Barrier  MPI_Bcast  MPI_Scatter  MPI_Gather  MPI_Scan  MPI_Reduce

MPI_Barrier() MPI_Barrier()  在组中建立一个同步栅栏。当每个进程都到达 MPI_Barrier 调用后,程序才接着往下执行:  MPI_Barrier (comm)

程序 7 、同步示例 程序 7 、同步示例 #include “mpi.h” #include “test.h” #include #include int main(int argc,char * * argv) { int rank,size,I; int rank,size,I; int *table; int *table; int errors=0; int errors=0; MPI_Aint address; MPI_Aint address; MPI_Datatype type,newtype; MPI_Datatype type,newtype; int lens; int lens; MPI_Init( &argc,&argv); MPI_Init( &argc,&argv); MPI_Comm_rank (MPI_COMM_WORLD,&rank); MPI_Comm_rank (MPI_COMM_WORLD,&rank); MPI_Comm_size (MPI_COMM_WORLD,&size); MPI_Comm_size (MPI_COMM_WORLD,&size);

/*Make data table */ /*Make data table */ table =(int *)calloc(size,sizeof(int)); table =(int *)calloc(size,sizeof(int)); table[rank]=rank+1; /* 准备要广播的数据 */ table[rank]=rank+1; /* 准备要广播的数据 */ MPI_Barrier (MPI_COMM_WORLD); MPI_Barrier (MPI_COMM_WORLD); /* 将数据广播出去 */ /* 将数据广播出去 */ for (i=0;i<size,i++) for (i=0;i<size,i++) MPI_Bcast( &table[i],1,MPI_INT,i,MPI_COMM_WORLD); MPI_Bcast( &table[i],1,MPI_INT,i,MPI_COMM_WORLD); /* 检查接收到的数据的正确性 */ /* 检查接收到的数据的正确性 */ for (i=0;i<size,i++) for (i=0;i<size,i++) if (table[i]!=i+1) errors++; if (table[i]!=i+1) errors++; MPI_Barrier(MPI_COMM_WORLD); /* 检查完毕后执行一次同步 */ MPI_Barrier(MPI_COMM_WORLD); /* 检查完毕后执行一次同步 */ …… …… /* 其他的计算 */ /* 其他的计算 */ MPI_Finalize(); MPI_Finalize();}

MPI_Bcast() MPI_Bcast()  从指定的一个根进程中把数据广播发送给组中 的所有其它进程:  MPI_Bcast (*buffer,count,datatype,root,comm)  对于 root 进程: buffer 既是接收缓冲又是发送缓 冲;对于其他进程: buffer 就是接收缓冲。

程序 8 、广播程序示例 程序 8 、广播程序示例 #include #include #include “mpi.h” int main (argc,argv) int argc; Char * * argv; { int rank,value; int rank,value; MPI_Init(&argc,&argv); MPI_Init(&argc,&argv); MPI_Comm_rank(MPI_COMM_WORLD,&rank); MPI_Comm_rank(MPI_COMM_WORLD,&rank);

do{ do{ if (rank==0) /* 进程 0 读入需要广播的数据 */ if (rank==0) /* 进程 0 读入需要广播的数据 */ scanf(“%d”,&value); scanf(“%d”,&value); /* 将该数据广播出去 */ /* 将该数据广播出去 */ MPI_Bcast(&value,1,MPI_INT,0,MPI_COMM_WORLD); MPI_Bcast(&value,1,MPI_INT,0,MPI_COMM_WORLD); /* 各进程打印收到的数据 */ /* 各进程打印收到的数据 */ printf(“Process %d got %d \n”,rank,value); printf(“Process %d got %d \n”,rank,value); }while(value>=0); }while(value>=0); MPI_Finalize(); MPI_Finalize(); return 0; return 0;}

MPI_Scatter() MPI_Scatter()  把根进程中的数据分散发送给组中的所有进程 (包括自己):  MPI_Scatter (*sendbuf,sendcnt,sendtype, *recvbuf, recvcnt,recvtype,root,comm) *recvbuf, recvcnt,recvtype,root,comm) root 用 MPI_Send(sendbuf, sendcount·n, sendtype, …) 发送一个消息。这个消息分成 n 个 相等的段,第 i 个段发送到进程组的第 i 个进程, sendcnt 必须要和 recvcnt 相同。 root 用 MPI_Send(sendbuf, sendcount·n, sendtype, …) 发送一个消息。这个消息分成 n 个 相等的段,第 i 个段发送到进程组的第 i 个进程, sendcnt 必须要和 recvcnt 相同。

MPI_Gather()  在组中指定一个进程收集组中所有进程发送来的 消息,这个函数操作与 MPI_Scatter 函数操作相 反:  MPI_Gather (*sendbuf,sendcnt,sendtype, *recvbuf, ecvcount,recvtype,root,comm) *recvbuf, ecvcount,recvtype,root,comm)

MPI_Reduce() MPI_Reduce()  在组内所有的进程中,执行一个规约操作,并 把结果存放在指定的一个进程中:  MPI_Reduce (*sendbuf,*recvbuf,count,datatype, op,root, comm) op,root, comm)  MPI 缺省定义了如下的规约操作,用户可根据 自己的需要用 MPI_Op_create 函数创建新的规 约操作:

程序 9 、规约示例 程序 9 、规约示例 #include “mpi.h” #include “mpi.h” #include #include double f(double x);/* 定义函数 f(x) */ double f(double x);/* 定义函数 f(x) */ { return(4.0/(1.0+x*x)); return(4.0/(1.0+x*x)); } int main (int argc,char * argv[]) int main (int argc,char * argv[]) { int done =0,n,myid,numprocs,i; int done =0,n,myid,numprocs,i; double PI25DT= ; double PI25DT= ; double mypi,pi,h,sum,x; double mypi,pi,h,sum,x; double startwtime=0.0,endwtime; double startwtime=0.0,endwtime; int namelen; int namelen; char processor_name[MPI_MAXPROCESSOR_NAME]; char processor_name[MPI_MAXPROCESSOR_NAME];

MPI_Init(&argc,&argv); MPI_Init(&argc,&argv); MPI_Comm_size(MPI_COMM_WORLD,&numprocs); MPI_Comm_size(MPI_COMM_WORLD,&numprocs); MPI_Comm_rank(MPI_COMM_WORLD,&myid); MPI_Comm_rank(MPI_COMM_WORLD,&myid); MPI_Get_processor_name(processor_name,&namelen); MPI_Get_processor_name(processor_name,&namelen); fprint(stdout,”Process %d of %d on % s\n”,myid,numprocs, fprint(stdout,”Process %d of %d on % s\n”,myid,numprocs, processor_name); processor_name); n=0; n=0; if (myid==0) if (myid==0) { printf(“Please give N=”); printf(“Please give N=”); scanf(&n); scanf(&n); startwtime=MPI_Wtime(); startwtime=MPI_Wtime(); } /* 将 n 值广播出去 */ /* 将 n 值广播出去 */ MPI_Bcast(&n,1,MPI_INT,0,MPI_COMM_WORLD); MPI_Bcast(&n,1,MPI_INT,0,MPI_COMM_WORLD);

h=1.0/(double) n; h=1.0/(double) n; sum=0.0; sum=0.0; for(i=myid+1;i<=n;i+=numprocs) for(i=myid+1;i<=n;i+=numprocs) /* 每一个进程计算一部分矩形的面积,若进程总数 numprocs 为 4 , /* 每一个进程计算一部分矩形的面积,若进程总数 numprocs 为 4 , 将 0-1 区间划分为 100 个矩形,则各个进程分别计算矩形块 将 0-1 区间划分为 100 个矩形,则各个进程分别计算矩形块 0 进程 1 , 5 , 9 , 13 , …… , 97 0 进程 1 , 5 , 9 , 13 , …… , 97 1 进程 2 , 6 , 10 , 14 , …… , 98 1 进程 2 , 6 , 10 , 14 , …… , 98 2 进程 3 , 7 , 11 , 15 , …… , 99 2 进程 3 , 7 , 11 , 15 , …… , 99 3 进程 4 , 8 , 12 , 16 , …… , 100 */ 3 进程 4 , 8 , 12 , 16 , …… , 100 */ { x=h*((double)i-0.5); x=h*((double)i-0.5); sum+=f(x); sum+=f(x); } mypi=h*sum; /* 各进程并行计算得到的部分和 */ mypi=h*sum; /* 各进程并行计算得到的部分和 */

/* 将部分和累加得到所有矩形的面积,该面积和即为近似 PI 值 */ /* 将部分和累加得到所有矩形的面积,该面积和即为近似 PI 值 */ MPI_Reduce(&mypi,&pi,1,MPI_DOUBLE,MPI_SUM,0, MPI_Reduce(&mypi,&pi,1,MPI_DOUBLE,MPI_SUM,0, MPI_COMM_WORLD); MPI_COMM_WORLD); if(myid==0) if(myid==0) { printf(“pi is approximately %.16f,Error is %.16f\n”, printf(“pi is approximately %.16f,Error is %.16f\n”, pi,fabs(pi-PI25DT)); pi,fabs(pi-PI25DT)); endwtime=MPI_Wtime(); endwtime=MPI_Wtime(); printf(“wall clock time=% f\n”,endwtime-startwtime); printf(“wall clock time=% f\n”,endwtime-startwtime); fflush(stdout); fflush(stdout); } MPI_Finalize(); MPI_Finalize(); }

MPI_Scan() MPI_Scan()  用来对分布在进程组上的数据执行前缀归约:  MPI_Scan (*sendbuf,*recvbuf,count, datatype,op,comm) datatype,op,comm)

群集函数的特点: 群集函数的特点:  通讯因子中所有进程都要调用  除了 MPI_Barrier(), 其他函数使用类似标准阻 塞的通信模式。一个进程一旦结束了它所参 与的群集操作就从群集例程中返回,并不保 证其他进程执行该群集例程已经完成。  一个群集例程是不是同步操作取决于实现。

MPI 并行程序的两种基本模式 MPI 并行程序的两种基本模式  对等模式的 MPI 程序设计  主从模式的 MPI 程序设计

一. 对等模式的 MPI 程序设计 1. 问题描述 ——Jacobi 迭代 Jacobi 迭代是一种比较常见的迭代方法, 其核心部分可以用程序 1 来表示。简单的说, Jacobi 迭代得到的新值是原来旧值点相邻数 值点的平均。 Jacobi 迭代是一种比较常见的迭代方法, 其核心部分可以用程序 1 来表示。简单的说, Jacobi 迭代得到的新值是原来旧值点相邻数 值点的平均。 Jacobi 迭代的局部性很好,可以取得很高 的并行性。将参加迭代的数据按块分割后, 各块之间除了相邻的元素需要通信外,在各 块的内部可以完全独立的并行计算。 Jacobi 迭代的局部性很好,可以取得很高 的并行性。将参加迭代的数据按块分割后, 各块之间除了相邻的元素需要通信外,在各 块的内部可以完全独立的并行计算。

程序 10 串行表示的 Jacobi 迭代 程序 10 串行表示的 Jacobi 迭代 …… REAL A(N+1,N+1),B(N+1,N+1) …… DO K=1,STEP DO J=1,N DO J=1,N DO I=1,N DO I=1,N B(I,J)=0.25*(A(I-1,J)+A(I+1,J)+A(I,J+1)+A(I,J-1)) B(I,J)=0.25*(A(I-1,J)+A(I+1,J)+A(I,J+1)+A(I,J-1)) END DO END DO DO J=1,N DO J=1,N DO I=1,N DO I=1,N A(I,J)=B(I,J) A(I,J)=B(I,J) END DO END DO END DO

2. 用 MPI 程序实现 Jacobi 迭代 2. 用 MPI 程序实现 Jacobi 迭代 为了并行求解,这里将参加迭代的数据按列进行分割,假设有 4 个进程同时并行计算,数据的分割结果如图:

假设需要迭代的数据是 M*M 的二维数组 A(M,M), 令 M=4*N, 按上 假设需要迭代的数据是 M*M 的二维数组 A(M,M), 令 M=4*N, 按上 图进行数据划分,则分布在 4 个不同进程上的数据分别是: 进程 0 : A(M,1:N); 进程 0 : A(M,1:N); 进程 1 : A(M,N+1:2*N); 进程 1 : A(M,N+1:2*N); 进程 2 : A(M,2*N+1:3*N); 进程 2 : A(M,2*N+1:3*N); 进程 3 : A(M,3*N+1:4*N). 进程 3 : A(M,3*N+1:4*N). 由于在迭代过程中,边界点新值的计算需要相邻边界其他块的 由于在迭代过程中,边界点新值的计算需要相邻边界其他块的 数据,因此在每一个数据块的两侧各增加 1 列的数据空间,用于 存放从相邻数据块通信得到的数据。每个数据块的大小就从 M*N 扩大到 M*(N+2) 。 计算和通信过程是这样的:首先对数组赋初值,边界赋为 8 , 计算和通信过程是这样的:首先对数组赋初值,边界赋为 8 , 内部为 0 。然后开始迭代,迭代之前,每个进程都需要从相邻的 进程得到数据块,同时也向相邻的进程提供数据块 (FORTRAN 数 组在内存中是按列优先排列的 ) 。

进程 0 进程 1 进程 2 进程 3 发送 接收

程序 11 、 并行的 Jacobi 迭代 程序 11 、 并行的 Jacobi 迭代 program main include ‘mpif.h’ integer totalsize,mysize,steps Parameter (totalsize=16) ( 定义全局数组的规模) parameter (mysize=totalsize/4,steps=10) integer n,myid,numprocs,i,j,rc Real a(totalsize,mysize+2),b(totalsize,mysize+2) Integer begin_col,end_col,ierr Integer status(MPI_STATUS_SIZE)

call MPI_INIT(ierr) call MPI_COMM_RANK(MPI_COMM_WORLD,myid,ierr) call MPI_COMM_SIZE(MPI_COMM_WORLD,numprocs,ierr) print *,”Process”,myid,” of”,numprocs,” is alive” ( 数组初始化 ) do j=1,mysize+2 do i=1,totalsize do i=1,totalsize a(i,j)=0.0 a(i,j)=0.0 end do end do end do If (myid.eq.0) then do i=1,totalsize do i=1,totalsize a(i,2)=8.0 a(i,2)=8.0 end do end do end if

If (myid.eq.3) then do i=1,totalsize do i=1,totalsize a(i,mysize+1)=8.0 a(i,mysize+1)=8.0 end do end do end if If (myid.eq.3) then do i=1,totalsize do i=1,totalsize a(i,mysize+1)=8.0 a(i,mysize+1)=8.0 end do end do end if do i=1,mysize+2 a(1,i)=8.0 a(1,i)=8.0 a(totalsize,i)=8.0 a(totalsize,i)=8.0 end do

(Jacobi 迭代部分 ) do n=1,steps ( 从右侧的邻居得到数据 ) if (myid.lt.3)then if (myid.lt.3)then call MPI_RECV(a(1,mysize+2),totalsize,MPI_REAL,myid+1, call MPI_RECV(a(1,mysize+2),totalsize,MPI_REAL,myid+1, 10,MPI_COMM_WORLD,status,ierr) 10,MPI_COMM_WORLD,status,ierr) end if end if ( 向左侧的邻居发送数据 ) if (myid.gt.0)then if (myid.gt.0)then call MPI_SEND(a(1,2),totalsize,MPI_REAL,myid-1, call MPI_SEND(a(1,2),totalsize,MPI_REAL,myid-1, 10,MPI_COMM_WORLD,ierr) 10,MPI_COMM_WORLD,ierr) end if end if

// 向右侧的邻居发送数据 if (myid.lt.3) then if (myid.lt.3) then call MPI_SEND(a(1,mysize+1),totalsize,MPI_REAL,myid+1, call MPI_SEND(a(1,mysize+1),totalsize,MPI_REAL,myid+1, 10,MPI_COMM_WORLD,ierr) 10,MPI_COMM_WORLD,ierr) end if end if // 从左侧的邻居接收数据 if (myid.gt.0) then if (myid.gt.0) then call MPI_RECV(a(1,1),totalsize,MPI_REAL,myid-1, call MPI_RECV(a(1,1),totalsize,MPI_REAL,myid-1, 10,MPI_COMM_WORLD,status,ierr) 10,MPI_COMM_WORLD,status,ierr) end if end ifbegin_col=2end_col=mysize+1

if (myid.eq.0) then begin_col=3 begin_col=3 end if end if if (myid.eq.3) then end_col=mysize end_col=mysize end if end if do j=begin_col,end_col do i=2,totalsize-1 do i=2,totalsize-1 b(i,j)=0.25*(a(i,j+1)+a(i,j-1)+a(i+1,j)+a(i-1,j)) b(i,j)=0.25*(a(i,j+1)+a(i,j-1)+a(i+1,j)+a(i-1,j)) end do end do

do j=begin_col,end_col do i=2,totalsize-1 do i=2,totalsize-1 a(i,j)=b(i,j) a(i,j)=b(i,j) end do end do end do do i=2,totalsize-1 print *,myid,(a(i,j),j=begin_col,end_col) print *,myid,(a(i,j),j=begin_col,end_col) end do call MPI_FINALIZE(rc) end

二. 主从模式的 MPI 程序设计 1. 问题描述 —— 矩阵向量乘 实现矩阵 C=A x B 。具体实现方法是:主进程将向量 B 广播 给所有的从进程,然后将矩阵 A 的各行依次发送给从进程, 从进程计算一行和 B 相乘的结果,然后将结果发送给主进程。 主进程循环向各个从进程发送一行的数据,直到将 A 各行的 数据发送完毕。一旦主进程将 A 的各行发送完毕,则每收到 一个结果,就向相应的从进程发送结束标志,从进程接收到 结束标志后退出执行。主进程收集完所有的结果后也结束。 实现矩阵 C=A x B 。具体实现方法是:主进程将向量 B 广播 给所有的从进程,然后将矩阵 A 的各行依次发送给从进程, 从进程计算一行和 B 相乘的结果,然后将结果发送给主进程。 主进程循环向各个从进程发送一行的数据,直到将 A 各行的 数据发送完毕。一旦主进程将 A 的各行发送完毕,则每收到 一个结果,就向相应的从进程发送结束标志,从进程接收到 结束标志后退出执行。主进程收集完所有的结果后也结束。

发送矩阵 A 的各行数据 回收各行与 B 相乘的结果 计算计算 计算计算 计算计算 计算计算 主进程 从进程

程序 12 、 矩阵向量乘 程序 12 、 矩阵向量乘 program main include “mpif.h” integer MAX_ROWS,MAX_COLS,rows,cols parameter (MAX_ROWS=1000,MAX_COLS=1000) double precision a(MAX_ROWS,MAX_COLS),b(MAX_COLS),c(MAX_COLS) double presicion buffer(MAX_COLS),ans integer myid,master,numprocs,ierr,status(MPI_STATUS_SIZE) integer i,j,numsent,numrcvd,sender integer anstype,row

call MPI_INIT(ierr) call MPI_COMM_RANK(MPI_COMM_WORLD,myid,ierr) call MPI_COMM_SIZE(MPI_COMM_WORLD,numprocs,ierr) master=0rows=100cols=100 If (myid.eq.master) then ( 主进程对矩阵 A 和 B 赋初值 ) ( 主进程对矩阵 A 和 B 赋初值 ) do i=1,cols do i=1,cols b(i)=1 b(i)=1 do j=1,rows do j=1,rows a(I,j)=1 a(I,j)=1 end do end do

numsent=0 numsent=0 numrcvd=0 numrcvd=0 ( 将矩阵 B 发送给所有其他的从进程,通过下面的广播语句实现 ) ( 将矩阵 B 发送给所有其他的从进程,通过下面的广播语句实现 ) call MPI_BCAST(b,cols,MPI_DOUBLE_PRECISION,master, call MPI_BCAST(b,cols,MPI_DOUBLE_PRECISION,master, * MPI_COMM_WORLD,ierr) ( 依次将矩阵 A 的各行发送给其他的 numprocs-1 个从进程 ) ( 依次将矩阵 A 的各行发送给其他的 numprocs-1 个从进程 ) do i=1,min(numprocs-1,rows) do i=1,min(numprocs-1,rows) do j=1,cols do j=1,cols ( 将一行的数据取出来依次放到缓冲区中 ) ( 将一行的数据取出来依次放到缓冲区中 ) buffer(j)=a(i,j) buffer(j)=a(i,j) end do end do ( 将准备好的一行数据发送出去 ) ( 将准备好的一行数据发送出去 ) call MPI_SEND(buffer,cols,MPI_DOUBLE_PRECISION,i,i, call MPI_SEND(buffer,cols,MPI_DOUBLE_PRECISION,i,i, * MPI_COMM_WORLD,ierr) numsent=numsent+1 numsent=numsent+1 end do end do

( 对所有的行,依次接收从进程对一行数据的计算结果 ) ( 对所有的行,依次接收从进程对一行数据的计算结果 ) do i=1,row do i=1,row call MPI_RECV(ans,1,MPI_DOUBLE_PRECISION,MPI_ANY_SOURCE, call MPI_RECV(ans,1,MPI_DOUBLE_PRECISION,MPI_ANY_SOURCE, * MPI_ANY_TAG,MPI_COMM_WORLD,status,ierr) sender=status(MPI_SOURCE) sender=status(MPI_SOURCE) anstype=status(MPI_TAG) anstype=status(MPI_TAG) ( 将该行数据赋给结果数组 C 的相应单元 ) ( 将该行数据赋给结果数组 C 的相应单元 ) c(anstype)=ans c(anstype)=ans ( 如果还有其他的行没有被计算,则继续发送 ) ( 如果还有其他的行没有被计算,则继续发送 ) if (numsent.lt.rows) then if (numsent.lt.rows) then do j=1,cols do j=1,cols ( 准备好新一行的数据 ) ( 准备好新一行的数据 ) buffer(j)=a(numsent+1,j) buffer(j)=a(numsent+1,j) end do end do ( 将该行数据发送出去 ) ( 将该行数据发送出去 ) call MPI_SEND(buffer,cols,MPI_DOUBLE_PRECISION,sender, call MPI_SEND(buffer,cols,MPI_DOUBLE_PRECISION,sender, * numsent+1,MPI_COMM_WORLD,ierr) numsent=numsent+1 numsent=numsent+1

else else ( 若所有行都已发送出去,则每接收一个消息则向相应的从进程发 ( 若所有行都已发送出去,则每接收一个消息则向相应的从进程发 送一个标志为 0 的空消息,终止该从进程的执行 ) 送一个标志为 0 的空消息,终止该从进程的执行 ) call MPI_SEND(1.0,0,MPI_DOUBLE_PRECISION,sender,0, call MPI_SEND(1.0,0,MPI_DOUBLE_PRECISION,sender,0, * MPI_COMM_WORLD,ierr) end if end if end do end doelse ( 下面为从进程的执行步骤,首先是接收数组 B) ( 下面为从进程的执行步骤,首先是接收数组 B) call MPI_BCAST(b,cols,MPI_DOUBLE_PRECISION,master, call MPI_BCAST(b,cols,MPI_DOUBLE_PRECISION,master, * MPI_COMM_WORLD,ierr) ( 接收主进程发送过来的矩阵 A 一行的数据 ) ( 接收主进程发送过来的矩阵 A 一行的数据 ) call MPI_RECV(buffer,cols,MPI_DOUBLE_PRECISION,master, call MPI_RECV(buffer,cols,MPI_DOUBLE_PRECISION,master, * MPI_ANY_TAG,MPI_COMM_WORLD,status,ierr)

( 若接收到标志为 0 的消息,则退出执行 ) ( 若接收到标志为 0 的消息,则退出执行 ) if (status(MPI_TAG).ne.0) then if (status(MPI_TAG).ne.0) then row=status(MPI_TAG) row=status(MPI_TAG) ans=0.0 ans=0.0 do I=1,cols do I=1,cols ans=ans+buffer(i)*b(j) ans=ans+buffer(i)*b(j) end do end do ( 计算一行的结果,并将结果发送给主进程 ) ( 计算一行的结果,并将结果发送给主进程 ) call MPI_SEND(ans,1,MPI_DOUBLE_PRECISION,master,row, call MPI_SEND(ans,1,MPI_DOUBLE_PRECISION,master,row, MPI_COMM_WORLD,ierr) MPI_COMM_WORLD,ierr) goto 90 goto 90 end if end if end if call MPI_FINALIZE(ierr) end