Насколько я вижу, это результат recv в цикле while на главном узле.
...
while (1) {
// Receive results from slave.
stat = world.recv(MPI_ANY_SOURCE,MPI_ANY_TAG);
...
Когда есть сообщение от одного ведомого, мастер не может получить никаких сообщений, пока код внутри цикла while не завершится (что занимает некоторое время, так как есть сон), поскольку главный узел не работает параллельно. Поэтому все остальные ведомые устройства не могут начать отправку своих сообщений, пока первое ведомое устройство не закончит отправку своего сообщения. Затем следующее подчиненное устройство может начать отправку сообщения, но затем все остальные подчиненные устройства останавливаются до тех пор, пока не будет выполнен код внутри цикла while.
Это приводит к поведению, которое вы видите, что связь ведомых устройств очень медленная. чтобы избежать этой проблемы, вам необходимо реализовать неблокирующую связь точка-точка или использовать глобальную связь.
ОБНОВЛЕНИЕ 1:
Предположим, что мастер распространил свои данные. Теперь он ждет, пока рабы не отчитаются. Когда первый подчиненный ответит, он сначала отправит свой REPORTTAG, а затем свой DONETAG. Теперь мастер отправит ему обратно новую работу, если
currentTask < numtasks
Теперь рабы снова начинают свой расчет. Возможно, сейчас дело обстоит так, что, пока он не закончил, хозяин мог обращаться только с другим рабом. Таким образом, подчиненный в начале теперь снова отправляет сначала свой REPORTTAG, а затем свой DONETAG и получает новую работу. Когда это продолжается, в конце концов, только 2 раба получили новую работу, а остальные не смогли закончить свою работу. Чтобы в какой-то момент это было правдой:
currentTask >= numtasks
Теперь вы останавливаете все задания, даже если не все ведомые устройства вернули свои данные и выполнили более одной задачи.
Эта проблема чаще всего возникает, когда сетевое соединение разных узлов сильно различается. Причина в том, что отправка и получение не обрабатываются после их вызова, вместо этого связь происходит, если две из этих функций могут выполнить какое-либо рукопожатие.
В качестве решений я бы предложил:
- Убедитесь, что все подчиненные завершены, прежде чем убивать все задания.
- Используйте сбор и разброс вместо сообщений, тогда все подчиненные синхронизируются после каждой задачи.
- Используйте буферизованные или небуферизованные операции отправки и получения, если сообщения не слишком большие. Убедитесь, что у вас не было переполнения памяти на Мастере
- Измените режим Master/Slave на более параллельный рабочий режим, например, разделите все задачи на два узла, затем разделите задачи дальше от этих узлов на следующие два и так далее. В конце отправьте задачу обратно. Это решение также может иметь то преимущество, что стоимость связи составляет всего O(logn), а не O(n).
Надеюсь, это помогло.
person
tune2fs
schedule
20.10.2011