Передача информации между потоками (foreach с %dopar%)

Я использую пакет doSNOW для распараллеливания задач, различающихся по длине. Когда один поток завершен, я хочу

  • некоторая информация, сгенерированная старыми потоками, передается следующему потоку
  • немедленно запустить следующий поток (балансировка нагрузки, как в clusterApplyLB)

Он работает в однопоточном режиме (см. makeClust(spec = 1))

#Register Snow and doSNOW
require(doSNOW)

#CHANGE spec to 4 or more, to see what my problem is
registerDoSNOW(cl <- makeCluster(spec=1,type="SOCK",outfile=""))

numbersProcessed <- c() # init processed vector
x <- foreach(i = 1:10,.export=numbersProcessed)  %dopar% {

    #Do working stuff
    cat(format(Sys.time(), "%X"),": ","Starting",i,"(Numbers processed so far:",numbersProcessed, ")\n")
    Sys.sleep(time=i)

    #Appends this number to general vector
    numbersProcessed <- append(numbersProcessed,i)

    cat(format(Sys.time(), "%X"),": ","Ending",i,"\n")
    cat("--------------------\n")
}

#End it all
stopCluster(cl)

Теперь измените спецификацию в «makeCluster» на 4. Вывод будет примерно таким:

[..]
Type: EXEC 
18:12:21 :  Starting 9 (Numbers processed so far: 1 5 )
18:12:23 :  Ending 6 
--------------------
Type: EXEC 
18:12:23 :  Starting 10 (Numbers processed so far: 2 6 )
18:12:25 :  Ending 7 

В 18:12:21 поток 9 знал, что потоки 1 и 5 уже обработаны. Через 2 секунды поток 6 заканчивается. Следующий поток должен знать хотя бы о 1, 5 и 6, верно? Но поток 10 знает только о 6 и 2.

Я понял, что это должно что-то делать с ядрами, указанными в makeCluster. 9 знает о 1, 5 и 9 (1+4+4), 10 знает о 2,6 и 10 (2+4+4).

Есть ли лучший способ передать «обработанный» материал последующим поколениям потоков?

Бонусные баллы: есть ли способ «печатать» на мастер-узле при параллельной обработке без этих сообщений «Type: EXEC» и т. д. из пакета snow? :)

Спасибо! Марк


person Marc    schedule 18.05.2014    source источник
comment
Вы не поняли, как работает цикл foreach. Это не цикл for. Прочитайте виньетку пакета foreach, чтобы узнать, как объединить результаты в один объект (кстати, увеличение объекта, например, использование append в цикле, является одним из основных грехов производительности в R). Насколько я знаю, вы можете выполнять полностью независимые (позорно параллельные) задачи только параллельно с foreach.   -  person Roland    schedule 18.05.2014
comment
@Roland Я подумал о чем-то вроде этого: основная программа порождает n рабочих потоков. Когда 1 из них завершен, основная программа извлекает результаты, возможно, выполняет небольшую постобработку (вывод на консоль информации о ходе выполнения, манипулирование глобальными переменными и т. д.) и порождает новую. Я не думаю, что это очень редкий вариант использования. Я уже знал, что первые n потоков не будут иметь информации о других (поскольку они выполняются, пока создается новый). В моем случае было бы достаточно, чтобы все данные были доступны на момент запуска нового процесса.   -  person Marc    schedule 18.05.2014


Ответы (1)


Виноват. Проклятие.

Я думал, что foreach с %dopar% является балансировкой нагрузки. Это не так, что делает мой вопрос абсолютным, потому что во время параллельной обработки на стороне хоста ничего не может быть выполнено. Это объясняет, почему глобальные переменные обрабатываются только на стороне клиента и никогда не достигают хоста.

person Marc    schedule 18.05.2014