2016-05-01 3 views
1

у меня есть этот код (примитив передачи тепла):Джулия значительно медленнее @parallel

function heat(first, second, m) 
    @sync @parallel for d = 2:m - 1 
     for c = 2:m - 1 
      @inbounds second[c,d] = (first[c,d] + first[c+1, d] + first[c-1, d] + first[c, d+1] + first[c, d-1])/5.0; 
     end 
    end 
end 

m = parse(Int,ARGS[1]) #size of matrix 
firstm = SharedArray(Float64, (m,m)) 
secondm = SharedArray(Float64, (m,m)) 

for c = 1:m 
    for d = 1:m 
     if c == m || d == 1 
      firstm[c,d] = 100.0 
      secondm[c,d] = 100.0 
     else 
      firstm[c,d] = 0.0 
      secondm[c,d] = 0.0 
     end 
    end 
end 
@time for i = 0:opak 
    heat(firstm, secondm, m) 
    firstm, secondm = secondm, firstm 
end 

Этот код дает хорошие времена, когда работать последовательно, но когда я добавляю @parallel его замедлить, даже если я бег на один нить. Мне просто нужно объяснение, почему это происходит? Код, только если он не изменяет алгоритм функции тепла.

+0

Я не уверен, что параллельное обновление/чтение различных элементов общего массива действительно работает. –

+0

@RezaAfzalan он должен работать нормально, если каждый участвующий процесс в 'SharedArray' работает только с его локальными индексами массива. Опыталась ли ОП [пример адвекции] (http://docs.julialang.org/en/latest/manual/parallel-computing/#id2) из ​​параллельных вычислений? Я нашел это очень полезным. Обратите внимание на границы, демаркированные «локальными индексами». –

+0

Несвязанные с параллельными вычислениями, но полезная привычка формироваться рано: в Юлии более эффективны заполнение 'firstm' и' secondm' столбцами вместо строк. Попробуйте поместить индекс 'd' во внешний цикл и переменную' c' во внутреннем цикле. –

ответ

8

Посмотрите на http://docs.julialang.org/en/release-0.4/manual/performance-tips/. Вопреки рекомендациям, вы много используете глобальные переменные. Считается, что они меняют типы в любое время, поэтому они должны быть помещены в коробку и распаковываться каждый раз, когда на них ссылаются. Этот вопрос тоже Julia pi aproximation slow страдает от того же. Чтобы сделать вашу функцию быстрее, глобальные переменные в качестве входных аргументов функции.

+0

Он решил мою проблему аппроксимации pi, но есть все переменные в функциональных параметрах. Как я сказал, это работает гладко, но только без @parallel. И жаль, что я забыл добавить итерацию к нагреву (она должна переключать эти матрицы). Отредактировано – pavelf

+0

Я думаю, что '@ sync' не требуется, и у меня есть улучшения без этого. Петли не имеют зависимости от предыдущих циклов, поэтому просто опустите это. –

+0

После удаления @sync он не возвращает правильный ответ. Также появились предупреждения. ПРЕДУПРЕЖДЕНИЕ: принудительное прерывание занятых работников ПРЕДУПРЕЖДЕНИЕ. Невозможно прекратить работу всех работников – pavelf

2

Есть несколько моментов для рассмотрения. Один из них - размер m. Если она мала, параллелизм даст много накладных расходов для не большой выигрыш:

julia 36967257.jl 4 
# Parallel: 
0.040434 seconds (4.44 k allocations: 241.606 KB) 
# Normal: 
0.042141 seconds (29.13 k allocations: 1.308 MB) 

Для больших m вы могли бы иметь лучшие результаты:

julia 36967257.jl 4000 
# Parallel: 
0.054848 seconds (4.46 k allocations: 241.935 KB) 
# Normal: 
3.779843 seconds (29.13 k allocations: 1.308 MB) 

Плюс два замечания:

1/инициализация могут быть упрощены до:

for c = 1:m, d = 1:m 
    if c == m || d == 1 
     firstm[c,d] = 100.0 
     secondm[c,d] = 100.0 
    else 
     firstm[c,d] = 0.0 
     secondm[c,d] = 0.0 
    end 
end 

2/ваша схема конечной разности не выглядит стабильным. Пожалуйста, взгляните на Linear multistep method или ADI/Crank Nicolson.

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