Высокопараллельная программа F # показывает плохое использование ЦП

Один из promises чистого функционального программирования состоит в том, что он хорошо разбирается. Я тестирую это требование, используя приложение F # со средними результатами. Моя программа запускает большое количество запросов MiniMax параллельно через Array.Parallel. Алгоритм MiniMax - это чистый функциональный код - без общего состояния, без блокировок, но очень рекурсивный, при создании и уничтожении множества значений при поиске по дереву. Нет ввода-вывода вообще - все в памяти. Каждый поиск MiniMax занимает 5-60 секунд, и я запускаю около 100 из них параллельно на быстрой коробке с 8 ядрами процессора. К сожалению, загрузка процессора достигает максимума около 65% и обычно находится в диапазоне 45-60%.

Я профилировал свое приложение с помощью Visual Studio Concurrency Visualizer и обнаружил, что он заблокирован примерно в 40% случаев. Все блокирующие вызовы, похоже, находятся в сборщике мусора .NET или других программах управления памятью .NET. Есть ли способ оптимизировать это поведение, не переписывая всю программу на языке более низкого уровня, например С++? Кажется очевидным, что проблема в том, что я создаю и уничтожаю слишком много объектов, но этого трудно избежать в идиоматическом коде F #. Возможно, я пропустил еще одну причину проблем синхронизации?

Спасибо.

Обновление: я сделал два изменения: отключил гиперпоточность и использовал gcServer в моем файле конфигурации. Это снизило время выполнения моего тестового примера с 32 до 13 секунд! Загрузка процессора также намного выше. Спасибо всем, кто внес предложения.

Ответ 1

Вы должны настроить приложение для использования сбора мусора сервера. См. Документацию по gcServer для получения более подробной информации. По умолчанию сборщик мусора рабочей станции просто не позволяет выделять тяжелые программы для масштабирования на несколько ядер.