pmap
имеет аргумент batch_size
, который по умолчанию равен 1. Это означает, что каждый элемент коллекции будет отправлен один за другим доступным рабочим процессам или задачам, которые будут преобразованы предоставленной вами функцией. Если каждый вызов функции выполняет большой объем работы и, возможно, каждый вызов отличается по времени, которое требуется, использование pmap
имеет то преимущество, что не позволяет рабочим процессам бездействовать, в то время как другие рабочие процессы выполняют работу, потому что, когда рабочий процесс завершает одно преобразование, он запрашивает следующий элемент для преобразования. Таким образом, pmap
эффективно распределяет нагрузку между работниками/задачами.
Однако @distributed
цикл for разделяет заданный диапазон между рабочими процессами один раз в начале, не зная, сколько времени займет каждый раздел диапазона. Рассмотрим, например, набор матриц, где первые сто элементов набора являются матрицами 2 на 2, следующие сто элементов являются матрицами 1000 на 1000, и мы хотели бы взять обратную каждую матрицу, используя @distributed
for-loops и 2 рабочих процесса.
@sync @distributed for i = 1:200
B[i] = inv(A[i])
end
Первый рабочий получит все матрицы 2 на 2, а второй получит матрицы 1000 на 1000. Первый рабочий очень быстро завершит все преобразования и будет простаивать, а другой будет продолжать выполнять работу очень долго. Несмотря на то, что вы используете 2 рабочих процесса, большая часть всей работы будет эффективно выполняться последовательно на втором рабочем потоке, и вы почти не получите никакой выгоды от использования более одного рабочего процесса. Эта проблема известна как балансировка нагрузки в контексте параллельных вычислений. Проблема также может возникнуть, например, когда один процессор работает медленно, а другой быстро, даже если работа, которую необходимо выполнить, является однородной.
Однако для очень небольших рабочих преобразований использование pmap
с небольшим размером пакета создает коммуникационные издержки, которые могут быть значительными, поскольку после каждого пакета процессор должен получить следующий пакет от вызывающего процесса, тогда как с @distributed
циклами for каждый рабочий процесс знать, в начале, за какую часть диапазона он отвечает.
Выбор между pmap
и @distributed
циклом for зависит от того, чего вы хотите достичь. Если вы собираетесь преобразовать коллекцию, как в map
, и каждое преобразование требует большого объема работы, и этот объем варьируется, то вам, вероятно, лучше выбрать pmap
. Если каждое преобразование очень маленькое, то вам, вероятно, лучше выбрать @distributed
цикла for.
Обратите внимание, что если вам нужна операция сокращения после преобразования, @distributed
цикл for уже предоставляет ее, большинство сокращений будет применяться локально, а окончательное сокращение будет выполняться в вызывающем процессе. Однако с pmap
вам придется самостоятельно обрабатывать сокращение.
Вы также можете реализовать свою собственную функцию pmap
с очень сложными схемами балансировки и уменьшения нагрузки, если она вам действительно нужна.
https://docs.julialang.org/en/v1/manual/parallel-computing/
person
hckr
schedule
16.04.2019