2016-12-04 5 views
0

Я новичок в параллельном программировании и собрал бит о R из разных (иногда противоречивых) источников. Я унаследовал какой-то код и попытался его распараллелить, я думаю, что правильная параллелизация данных.ClusterMap в R на разветвленном кластере намного медленнее, чем mapply. Что еще я могу попробовать?

Задача требует некоторых вычислений по нескольким индивидам (фаза 1), затем вычисляемые величины используются для вычисления некоторой характеристики популяции (фаза 2). Мы делаем это для цикла над некоторым заданным числом итераций. У меня есть подозрение (соединяя биты, которые я прочитал), что вычисления из фазы 1 вызывают изменение объекта, хранящего результаты, которые делают вычисление, страдают от некоторого времени ожидания, вызванного (нежелательным) копированием объектов. Результатом является выполнение программы с использованием clusterMap с гораздо большим системным временем, чем непараллелизированная версия кода с использованием mapply.

Расчеты требуют много уровней вызовов функций. Я попытался дать представление о структуре кода в небольшом рабочем примере ниже.

require(parallel) 

## define the two phases of the computation 
phase1.top.level<- function(x,y){second.level(x,y)} 

## Functions call other functions. 
phase1.second.level<- function(x,y){ third.level(x,y) } 

phase1.third.level<- function(x,y){ result<- x^2-2*y*x; result } 

## define the function that performs the second phase of the computation  
second.phase<-function(input,x,y) {input+x+y} 

## Assemble these functions into an algorithm 
multi.phase.comp<- function(input,x,y){ 

    input<-phase1.top.level(x,y) 
     output<-second.phase(input,x,y) 
} 


### Call the function with inputs 
x<-seq(1:100) 
y<-seq(1:100) 
input<-rep(1,100) 

## Time the function executed for the vector inputs using clusterMap from the parallel package 
system.time({ 
no_cores<-5 
    c1<- makeCluster(no_cores,type="FORK") 
out<- clusterMap(cl=c1, multi.phase.comp, input, x, y) 
stopCluster(c1) 
}) 
### One execution of this (on an old laptop) gave 
### user system elapsed 
### 0.055 0.163 0.973 

## Regrettably, the effort to parallelise wasn't justified as mapply is faster: 
system.time({ 
out2<- mapply(multi.phase.comp, input, x, y) 
}) 
#### This shows much less system and elapsed time 
#### user system elapsed 
#### 0.009 0.002 0.030 

Любые предложения о том, как ускорить мой код? Будет ли я лучше с кластерами сокетов для этого типа приложений?

+0

Проблемы с почти никаким временем вычисления не стоит выполнять параллельно, поскольку время вычислений намного меньше, чем накладные расходы на отправку задач и получение результатов от работников. Если задачи в вашей реальной задаче занимают даже 0,1 секунды для выполнения, параллельная версия должна бить mapply. Но нет смысла пытаться улучшить производительность этой игрушечной проблемы, так как вы никогда не сможете бить 0,03 секунды. –

+0

@SteveWeston действительный код гораздо более задействован, и слишком длинный и запутанный, чтобы служить иллюстрацией. Вот реализация фактического времени работы: Открытие кластера в одном из нижних уровней функции дает система пользователя истекшее 12,219 1,390 29,283 так что вы можете видеть время, прошедшее гораздо больше времени (не хорошо) обработки Но если я использую кластер в двух местах, я получаю пользовательскую систему, истекшую 11.029 1.763 71.022 Использование только mapply дает время в 5-7 секунд. –

+0

Что произойдет, если вы используете 'mcmapply (multi.phase.comp, input, x, y, mc.cores = no_cores)' (без каких-либо makeCluster, stopCluster)? –

ответ

2

Параллельный пакет не подходит для такого типа мелкомасштабных параллельных вычислений, в основном потому, что он использует процессы, а не потоки, как рабочие. Однако, если у вас есть очень много небольших задач (например, миллион, а не сто), вы можете использовать методы квантования для повышения производительности.

Вот пример, который использует mclapply:

# return list of arguments to seq function 
slices <- function(n, chunks) { 
    if (n <= 0) return(list()) 
    chunks <- min(chunks, n) 
    m <- n %/% chunks 
    length.out <- rep(m, chunks) 
    r <- n - m * chunks 
    length.out[seq_len(r)] <- length.out[seq_len(r)] + 1 
    from <- cumsum(c(1, length.out[-chunks])) 
    mapply(c, from, length.out, SIMPLIFY=FALSE) 
} 

# compute result for a segment of the input vectors 
wraptask <- function(il) { 
    i <- seq(il[1], length.out=il[2]) 
    mapply(multi.phase.comp, input[i], x[i], y[i]) 
} 

system.time({ 
    out3 <- do.call('c', 
        mclapply(slices(length(x), no_cores), 
          wraptask, mc.cores=no_cores)) 
}) 

Когда я побежал это на примере, но с использованием входных векторов с миллионом элементов, mapply взял 5,8 секунды, а оптимизированная mclapply взял 2,1 секунды. Это впечатляет в некотором смысле, но многие могут подумать, что нужно много работы, чтобы сэкономить 3 секунды времени вычисления.

+0

ah Уве Максим: «Компьютеры дешевы и думают, что болит». Я все еще впечатлен выигрышем и могу видеть, могу ли я применить это мышление к исходной проблеме и коду. Благодаря! –

Смежные вопросы