【发布时间】:2019-05-23 23:13:05
【问题描述】:
我正在尝试使用 MPI 实现矩阵向量乘法(即 nxn 矩阵乘以 nx1 向量)。
最初,我决定使用多个MPI_Bcast 调用(在我注意到MPI_AllGather...之前),我偶然发现了一些奇怪的行为。显然,无论传递给MPI_Bcast调用什么等级,都可以接收数据。
使用的部分代码(函数在彼此之后调用,因此发送广播在接收广播之前)。打印仅用于调试目的,我知道测试数据的长度为 2:
class Processor
{
public:
Processor(int rank, int communicatorSize);
private:
void broadcastOwnVectorToOtherRanks();
void receiveBroadcastsFromOtherRanks();
//...
int ownRank;
int communicatorSize;
std::vector<int> ownVectorPart;
std::vector<int> totalVector;
//...
};
void Processor::broadcastOwnVectorToOtherRanks()
{
//ownVectorPart is correctly filled before this function call
std::printf("Own data in vector %d %d\n", ownVectorPart[0], ownVectorPart[1]);
MPI_Bcast(ownVectorPart.data(), ownVectorPart.size(), MPI_INT, ownRank, MPI_COMM_WORLD);
}
void Processor::receiveBroadcastsFromOtherCommunicators()
{
for (int rank = 0; rank < communicatorSize; ++rank)
{
if (rank == ownRank)
{
totalVector.insert(totalVector.end(), ownVectorPart.begin(), ownVectorPart.end());
}
else
{
std::vector<int> buffer(ownVectorPart.size());
MPI_Bcast(buffer.data(), ownVectorPart.size(), MPI_INT, rank, MPI_COMM_WORLD);
std::printf("Received from process with rank %d: %d %d\n", rank, buffer[0], buffer[1]);
totalVector.insert(totalVector.end(), buffer.begin(), buffer.end());
}
}
}
结果(按等级排序):
[0] Own data in vector 0 1
[0] Received from communicator 1: 6 7
[0] Received from communicator 2: 4 5
[0] Received from communicator 3: 2 3
[1] Own data in vector 2 3
[1] Received from communicator 0: 0 1
[1] Received from communicator 2: 4 5
[1] Received from communicator 3: 6 7
[2] Own data in vector 4 5
[2] Received from communicator 0: 0 1
[2] Received from communicator 1: 2 3
[2] Received from communicator 3: 6 7
[3] Own data in vector 6 7
[3] Received from communicator 0: 4 5
[3] Received from communicator 1: 2 3
[3] Received from communicator 2: 0 1
如您所见,在进程中接收到的 rank 0 和 3 数据与发送的数据不同。例如,等级为0 的进程从等级3 接收数据,即使它期待来自进程1 的数据。
在我看来,在接收广播数据时会忽略排名,而 MPI 会在数据到来时分配数据,无论它是否来自预期的排名。
为什么MPI_Bcast 接收来自秩为3 的进程的数据,而作为参数传递的秩是1?同时多次调用MPI_Bcast 是一种未定义的行为吗?还是我的代码有错误?
【问题讨论】:
-
您将传播者与根等级混合在一起。在您的 sn-p 中,只有一个通信器,它是
MPI_COMM_WORLD。通信器的所有等级都必须以 same 根等级调用MPI_Bcast(),我怀疑您的程序中不是这种情况,因此是未定义的行为。如果您需要更多帮助,请上传minimal reproducible example。 -
@GillesGouaillardet 是的,很抱歉对沟通者和等级造成混淆。我的问题是,所有队伍都在尝试广播数据。首先,每个 rank 发送单个广播(
broadcastOwnVectorToOtherCommunicators()),其次每个 rank 尝试接收来自所有其他 rank 的广播(receiveBroadcastsFromOtherCommunicators())。多个广播正在同时交换。我将编辑问题以尝试清除它。 -
是的,所有广播都已接收。例如等级为
3的进程将发送一个广播并从0、1和2接收总共3 个广播。但是接收到的数据是混杂的,好像MPI_Bcast中的rank参数被忽略了一样。 -
再一次,您可能误用了
MPI_Bcast()。通信器的所有等级必须调用具有相同root参数的集体子例程。如果您使用minimal reproducible example编辑您的问题,我只能确认它 -
@GillesGouaillardet 完整示例中缺少什么?
main()?qsub的 PBS 文件?我可以重构它以避免类来尝试简化它?我试图解释所有进程都会用给定的root最终调用MPI_Bcast。所有进程都会在某个时候使用root == 0、root == 1等调用它。如果不允许这样做,这就是我要问的全部内容。