前文说到,mpi是信息传递接口,因此信息传递是mpi的重点.而进程中的信息传递就是进程通信!今天我们将看看mpi创建的一组进程是怎么相互通信的.
进程通信有许多种,点对点通信,广播,散播等.今天我们先学习点对点通信.
什么是点对点通信?其实就是最简单的进程A向进程B发送信息,而进程B向进程A接收信息.这是关于两个进程之间的通信.
代码:
运行结果:
代码解释:
我们看见,进程1得到了进程0的数据,一个int,值为1.
使用到的一组方法是comm对象的send和recv.
send方法的第一个参数就是你要传送的数据,这个数据可以是一个int,一个float,还可以是列表,字典,甚至是numpy的array对象(你可以试一下)
send方法还有一个dest参数,这就是你想发送的进程的rank.
而recv方法在这里只使用了一个参数source,就是你要指定的发送方进程的rank.
阻塞or非阻塞?
一谈到消息传递,大家都会想到同步异步的问题,这就涉及到函数的阻塞性.那么,上面的send和recv方法是阻塞函数还是非阻塞函数?
recv是阻塞函数,也就是说进程要收到发送方的数据,这个函数才返回.
而send是不确定的,也就是说它有时候是阻塞,有时候是非阻塞.当发送的数据不多的时候,mpi会将数据存到一个系统缓冲区,然后马上进行send方法的返回.而当数据量很大超过缓冲区的大小的时候,mpi需要等待接收方接收,然后把数据拷贝给接收方,再进行send方法的返回.
简单来说,数据量少->非阻塞,数据量大->阻塞.
小写or大写?
细心的同学还会发现,comm对象除了send和recv方法,还有Send和Recv方法.一个字母小写和大写之差,到底意味着什么?
事实上,不止send和recv方法,以后学到的所有信息传递方法都会有这小写大写两个版本.
这里参考官方文档说法,这样区分是由于要传递的数据的性质差异.当我们要传递int,float,list,dict等python内置类型的数据的时候,我们使用小写的方法.而当使用buffer类型的数据的时候,我们要使用大写的方法.
buffer类型是什么意思我还未理解,希望有人告诉我一下.
send的多个版本:
事实上,除了大写小写的版本,send还有不同的版本,这个不同是基于不同的发送策略的,而这些版本都有大小写之分.
bsend:缓冲模式,数据写入缓冲区,马上返回,用户必须确保缓冲区大小足够
ssend:同步模式,等接收方接收才返回
rsend:就绪模式,发送时必须确保接收方处于等待接收的状态,否则产生错误
send:标准模式(bsend+ssend)
send实际上就是bsend和ssend的结合体.而rsend的意义我暂时不知道,一般在初学的时候,我们就使用标准模式send就好了.
另一种意义的阻塞or非阻塞
除了大小写之外,mpi还为大部分的通信函数提供了阻塞和非阻塞这两种方式,非阻塞的在阻塞版本的前面加i或者I.例如isend,ibsend,issend,irsend.
不是说bsend就是非阻塞了吗,那ibsend又是什么意思?
这里的阻塞是针对信息的拷贝工作的.当使用bsend的时候,数据拷贝到缓冲区后,函数才返回.而使用ibsend的时候,拷贝的工作是交给mpi后台来完成,而在实际进行拷贝的时候,函数早已经返回了.
总结:
实际上,除了send,其他版本的send我都没有用过,这些版本在这里也只是知识的拓展,以后如果有需要,会另外详细说明其原理和用法.