Я использую библиотеку параллельных задач из .NET Framework 4 (в частности, Parallel.For
и Parallel.ForEach
), однако я получаю чрезвычайно посредственные ускорения при распараллеливании некоторых задач, которые выглядят так, как будто их легко распараллелить на двойной Основная машина.
При профилировании системы похоже, что из-за сборщика мусора происходит большая синхронизация потоков. Я много занимаюсь размещением объектов, поэтому мне интересно, как я могу улучшить параллелизм при минимальном переписывании моего кода.
Например, есть некоторые методы, которые могут быть полезны в этой ситуации:
- Стоит ли пытаться управлять ГХ вручную?
- Должен ли я использовать
Dispose
?
- Должен ли я прикреплять объекты?
- Должен ли я делать другие опасные трюки с кодом?
Постскриптум:
Проблема не в том, что GC запускается слишком часто, а в том, что GC препятствует эффективной параллельной работе параллельного кода. Я также не считаю «распределять меньше объектов» приемлемым ответом. Для этого требуется переписать слишком много кода, чтобы обойти плохо распараллеленный сборщик мусора.
Я уже нашел один трюк, который помогал повысить общую производительность ( с использованием gcServer ), но не помогал одновременной производительности. Другими словами, Parallel.For
был только на 20% быстрее, чем последовательный цикл For, для смущающе параллельной задачи.
POST-Постскриптум:
Хорошо, позвольте мне объяснить подробнее, у меня довольно большая и сложная программа: оптимизирующий интерпретатор. Это достаточно быстро, но я хочу, чтобы его производительность выполнялась, когда выполняемые параллельные задачи (примитивные операции встроены в мой язык) хорошо масштабируются и доступно больше ядер. Я выделяю много мелких объектов во время оценки. Весь дизайн интерпретатора основан на том, что все значения получены из одного полиморфного базового объекта. Это прекрасно работает в однопоточном приложении, но когда мы пытаемся применить Task Parallel Library для параллельных вычислений, это не дает никаких преимуществ.
После долгих исследований того, почему библиотека параллельных задач не распределяла должным образом работу между ядрами для этих задач, похоже, виновником является GC. Похоже, что GC действует как узкое место, потому что он выполняет некоторую синхронизацию потоков сцены, которую я не понимаю.
Что мне нужно знать, так это: что именно делает GC, что может привести к плохой работе сильно параллельного кода, когда он выполняет много выделений, и как мы можем обойти это , отличное от просто выделение меньшего количества объектов . Такой подход мне уже приходил в голову и потребовал бы значительного переписывания большого количества кода.