ТЛ; др
Я получаю лучшую производительность с моей программой erlang, когда я выполняю задачи с интенсивным использованием ЦП при более высоком параллелизме (например, 10K за раз против 4). Почему?
<ч />
Я пишу каркас сокращения карт, используя erlang, и я делаю тесты производительности.
Моя функция карты сильно загружает процессор (в основном чистый расчет). Ему также требуется доступ к некоторым статическим данным, поэтому у меня есть несколько постоянных (т. Е. Длится, т. Е. Проходит через жизненный цикл приложения) рабочих процессов на моей машине, каждый из которых имеет часть этих данных в памяти и ожидает запросов карты. Выходные данные карты отправляются процессу менеджера (который отправлял запросы на карту рабочим), где выполняется уменьшение (очень легкое).
В любом случае, я заметил, что у меня улучшается пропускная способность, когда я немедленно запускаю новый процесс для каждого запроса карты, который получают рабочие, вместо того, чтобы позволить самому рабочему процессу синхронно выполнять запрос карты один за другим ( таким образом оставляя кучу запросов карты в его очереди процесса, потому что я запускаю запросы карты все сразу).
Фрагмент кода:
%% When I remove the comment, I get significant performance boost (90% -> 96%)
%% spawn_link(fun()->
%% One invocation uses around 250ms of CPU time
do_map(Map, AssignedSet, Emit, Data),
Manager ! {finished, JobId, self(), AssignedSet, normal},
%% end),
По сравнению с тем, когда я выполняю те же вычисления в узком цикле, я получаю 96% -ую пропускную способность (эффективность), используя метод «немедленного появления» (например, 10000 карт сокращают задания, выполняющиеся полностью параллельно). Когда я использую метод «работник выполняет один за другим», я получаю только около 90%.
Я понимаю, что Эрланг, как предполагается, хорош в параллельных вещах, и я впечатлен тем, что эффективность не меняется, даже если я выполняю запросы уменьшения карты на 10 Кб одновременно, в отличие от 100 и т. Д.! Тем не менее, поскольку у меня всего 4 ядра ЦП, я ожидал бы получить более высокую пропускную способность, если бы использовал более низкий параллелизм, например 4 или, возможно, 5.
Странно, но загрузка моего ЦП в двух разных реализациях выглядит очень похоже (почти полностью привязана к 100% на всех ядрах). Разница в производительности довольно стабильна. То есть даже когда я просто выполняю задания по сокращению на 100 карт, я все равно получаю около 96% эффективности с помощью метода «немедленно порождать» и около 90% при использовании метода «один за другим». Аналогично, когда я тестирую с 200, 500, 1000, 10K заданиями.
Сначала я подозревал, что виноват в очереди в очереди рабочих процессов, но даже когда в очереди рабочих процессов должно быть что-то вроде 25 сообщений, я все равно вижу более низкую производительность. 25 сообщений кажутся достаточно маленькими для того, чтобы вызвать засорение (я делаю выборочное сопоставление сообщений, но не так, чтобы процесс должен был помещать сообщения обратно в очередь).
Я не уверен, как мне поступить отсюда. Я делаю что-то не так или я что-то упускаю?
ОБНОВЛЕНИЕ
Я провел еще несколько тестов и обнаружил, что разница в производительности может исчезнуть в зависимости от условий (в частности, на сколько рабочих процессов я делю статические данные). Похоже, мне нужно многому научиться!