Scala делает что-то параллельно самостоятельно? - PullRequest
7 голосов
/ 07 июня 2011

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

Программа рассчитывает 30 лабиринтов с увеличением размеров.Использование для понимания более (от 1 до 30)

Поскольку в последних версиях стала доступна инфраструктура параллельных коллекций, я подумал об этом, надеясь на некоторое повышение производительности.

Это не удалось, и когда я немного исследовал, я обнаружил следующее:

  1. При запуске без какого-либо вызова к чему-либо удаленно параллельному, он по-прежнему показывал загрузку процессора около 30% на каждом из 4 ядер моей машины.

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

  3. Замена некоторых внутренне используемых коллекций их параллельными счетными частями, похоже, дала эффект.

Теперь у меня есть 2 вопроса:

  • Почему у меня вращаются все 4 ядра, хотя параллельно ничего не работает.

  • Что может быть причиной того, что программа все еще занимает одно и то же время, независимо от того, работает ли она параллельно или нет.Нет очевидных других узких мест, кроме циклов ЦП (нет ввода-вывода, нет сети, много памяти через настройку -Xmx)

Есть идеи по этому поводу?

1 Ответ

9 голосов
/ 07 июня 2011

30% на версию ядра - просто плохой планировщик (звучит как Windows 7), очень часто переносящий процесс с ядра на ядро. Вероятно, это ближе к 25% на ядро ​​(1/4) для вашего процесса плюс дополнительная нагрузка, составляющая 30%. Если вы запустите тот же пример под Linux, вы, вероятно, увидите одно ядро ​​в привязке.

Когда вы преобразовали в (1 to 30).par, вы действительно начали использовать потоки на всех ядрах, но накладные расходы на синхронизацию распределения такого небольшого объема работы и последующего сбора результатов сводили на нет преимущества параллелизма. Вы должны разбить свою работу на более крупные независимые куски.

РЕДАКТИРОВАТЬ: если каждый из 1..30 представляет некоторый больший объем работы (скажем, решение лабиринта), то автоматическое распараллеливание будет работать намного лучше, если каждая единица работы примерно одинакова. Представьте, что у вас было 29 легких лабиринтов и один очень очень твердый лабиринт. 30-й лабиринт все еще будет работать последовательно (или почти) со всем остальным). Если ваши лабиринты усложняются по количеству, попробуйте создать их в порядке 30 to 1 by -1, чтобы самые большие задачи выполнялись первыми. Думайте об этом как о мозговом решении проблемы ранца.

...