Параллельная реализация медленнее последовательной в Юлии - PullRequest
6 голосов
/ 20 июня 2020

Почему в следующем коде Джулии параллельная реализация выполняется медленнее, чем последовательная?

using Distributed

@everywhere function ext(i::Int64)
   callmop = `awk '{ sum += $1 } END { print sum }' infile_$(i)`
   run(callmop)
end

function fpar()
   @sync @distributed for i = 1:10
      ext(i)
   end
end

function fnopar()
   for i = 1:10
      ext(i)
   end
end

val, t_par, bytes, gctime, memallocs = @timed fpar()
val, t_nopar, bytes, gctime, memallocs = @timed fnopar()

println("Parallel: $(t_par) s. Serial: $(t_nopar) s")  
# Parallel: 0.448290379 s. Serial: 0.028704802 s

Файлы infile_$(i) содержат единственный столбец действительных чисел. После некоторого исследования я наткнулся на этот пост и этот другой пост ), которые касаются схожих проблем. Хотя они кажутся немного устаревшими, если принять во внимание скорость развития Джулии. Есть ли способ улучшить этот параллельный участок? Заранее большое спасибо.

1 Ответ

7 голосов
/ 20 июня 2020

Ваш код правильный, но вы неверно измеряете производительность.

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

Когда функция Julia выполняется в первый раз, она компилируется. Когда вы выполняете его в нескольких параллельных процессах, всем им необходимо скомпилировать один и тот же фрагмент кода.

Вдобавок к этому первый запуск макроса @distribution также занимает много времени для компиляции. Следовательно, перед использованием @timed вы должны один раз вызвать обе функции fpar и nofpar.

И последнее, но не менее важное: в вашем коде нет addprocs, но я предполагаю, что вы использовали -p Возможность Julia добавить рабочие процессы в ваш главный процесс Julia. Между прочим, вы не упомянули, сколько у вас рабочих процессов.

Я обычно тестирую такой код:

@time fpar()
@time fpar()
@time fnopar()
@time fnopar()

Первая мера - понять время компиляции, а вторая измерьте время выполнения.

Также стоит взглянуть на пакет BenchmarkTools и макрос @btime.

Что касается тестов производительности, то @distributed имеет значительные накладные расходы на связь . В некоторых сценариях ios это можно смягчить, используя SharedArrays, в других - используя Thread.@threads. Однако в вашем случае самым быстрым кодом будет тот, который использует зеленые потоки:

function ffast()
   @sync for i = 1:10
      @async ext(i)
   end
end
...