Как я могу улучшить производительность сборщика "мусора".NET 4.0 в очень параллельном коде?

Я пользуюсь библиотекой параллели задачи от платформы.NET 4 (конкретно Parallel.For и Parallel.ForEach) однако я получаю чрезвычайно посредственные ускорения при параллелизации некоторых задач, которые похожи, они должны быть легко параллелизированы на двухъядерной машине.

В профилировании системы похоже, что существует большая синхронизация потока, продолжающаяся из-за сборщика "мусора". Я делаю большое выделение объектов, таким образом, я задаюсь вопросом, как я могу улучшить параллелизм при уменьшении переписывания моего кода.

Например, есть ли некоторые методы, которые могут быть полезными в этой ситуации:

  • Я должен попытаться управлять GC вручную?
  • Если я использую Dispose?
  • Я должен прикреплять объекты?
  • Я должен делать другие небезопасные приемы кода?

POSTSCRIPT:

Проблемой не является GC, работающий слишком часто, случается так, что GC препятствует тому, чтобы параллельный код был выполнением параллельно эффективно. Я также не рассматриваю, "выделяют меньше объектов", чтобы быть приемлемым ответом. Это требует, чтобы перезапись слишком большого количества кода работала вокруг плохо параллелизированного сборщика "мусора".

Я уже нашел один прием, который помог общей производительности (использующий gcServer), но это не помогло параллельной производительности. Другими словами, Parallel.For было только на 20% быстрее, чем сериал Для цикла, на смущающе параллельной задаче.

ПОСТ-POSTSCRIPT:

Хорошо, позвольте мне объяснить далее, у меня есть довольно большая и сложная программа: интерпретатор оптимизации. Это достаточно быстро, но я хочу его производительность, когда данный параллельные задачи (примитивные операции, встроенные в мой язык) для масштабирования хорошо, поскольку, больше ядер доступно. Я выделяю много маленького объекта во время оценок. Целый дизайн интерпретатора основан на всех значениях, получаемых из единственного полиморфного базового объекта. Это работает отлично в однопоточном приложении, но когда мы пытаемся применить Библиотеку Параллели Задачи, чтобы быть параллельными оценкам нет никакого преимущества.

После большого расследования того, почему Библиотека Параллели Задачи правильно не распределяла работу через ядра для этих задач, кажется, что преступником является GC. По-видимому, GC, кажется, действует как узкое место, потому что он делает некоторых позади синхронизации потока сцены, которую я не понимаю.

То, что я должен знать: что точно является GC, делающим, который может заставить в большой степени параллельный код работать плохо, когда он делает много выделений, и как мы можем работать вокруг этого кроме просто выделения меньшего количества объектов. Тот подход уже произошел со мной и потребовал бы, чтобы значительное переписало большого количества кода.

12
задан cdiggins 22 February 2010 в 20:25
поделиться

7 ответов

Если сборщик мусора запускается слишком часто из-за того, что слишком много объектов выделяется / редактируется сборщиком мусора, попробуйте выделить их меньше :)

В зависимости от вас сценарий - попробуйте повторно использовать существующие объекты, создать пул объектов, использовать «более легкие» объекты, которые не создают такой большой нагрузки на память (или больше, чтобы уменьшить количество выделенных объектов).

Не пытайтесь «управлять сборщиком мусора», явно вызывая GC.Collect, это очень редко окупается ( Рико Мариани так говорит )

или http: //blogs.msdn.com / ricom / archive / 2003/12/02 / 40780.aspx

5
ответ дан 2 December 2019 в 21:02
поделиться

1) Вы не можете и не должны управлять GC вручную.

2) Dispose - это только указание для GC, он в любом случае передаст его, когда посчитает нужным. :P

Единственный способ избежать этих проблем - это профилировать ваше приложение и стараться, насколько это возможно, избегать выделения новых объектов. Когда вы выясните, что попадает в сборщик мусора, попробуйте использовать какую-нибудь технику объединения в пул, чтобы повторно использовать эти данные и не создавать их каждый раз заново.

EDIT : Когда работает GC, ВСЕ потоки должны перейти в состояние сна, чтобы позволить ему сделать свою работу. Это причина замедления, если коллекций много, как в вашем случае. Нет другого способа справиться с этим, кроме как уменьшить генерацию новых объектов.

2
ответ дан 2 December 2019 в 21:02
поделиться

По вашим четырем пунктам:

  1. См. Как я могу улучшить производительность сборщика мусора .NET 4.0 в код с высокой степенью параллелизма? (1)
  2. Вы должны удалить, если ваши объекты содержат ресурсы, особенно ресурсы для неуправляемых объектов. Dispose выполняется немедленно. Возможный финализатор (~ деструктор в C ++) вызывается только тогда, когда запускается сборщик мусора и объект удаляется из памяти.
  3. Закрепление объектов имеет смысл только в том случае, если объект передается в неуправляемый фрагмент кода, например неуправляемая dll c ++. В противном случае оставьте сборщик мусора, который будет делать свою долю в поддержании порядка в памяти. Закрепление также может привести к фрагментации памяти.
  4. Нет, если вам не нужно.

Одна вещь, о которой следует подумать, - это переместить выделение из ваших циклов - если это возможно. Во многих случаях, когда вы можете это сделать, это также позволяет вам повторно использовать уже выделенные объекты, тем самым обеспечивая дополнительную производительность (по крайней мере, то, что показывает мой опыт) (см. Также Как я могу улучшить производительность сборщика мусора .NET 4.0 в коде с высокой степенью параллелизма? ).

Степень параллельного выполнения всегда зависит от задачи, которую вы выполняете, в случае вычисления максимально достижимый параллелизм составляет

2
ответ дан 2 December 2019 в 21:02
поделиться

Это жизненный факт. Почти все схемы управления памятью в той или иной степени сериализуют код, который выглядит неловко параллельным. Я думаю, что в C# есть потоково-локальные аллокаторы, поэтому он должен сериализовать только коллекции. Тем не менее, я бы рекомендовал объединять/использовать наиболее часто выделяемые объекты и массивы и, возможно, преобразовать некоторые небольшие неполиморфные объекты в структуры и посмотреть, поможет ли это.

1
ответ дан 2 December 2019 в 21:02
поделиться

Если установить тэг изображения src равным # или очистить его, это вызовет двойную загрузку страницы, я столкнулся с этим на хром и до на firefox.

Вы можете поместить любой символ или последовательность вместо пустого или #, чтобы решить эту проблему.

-121--1328170-

Это грязный взлом, но он, кажется, работает.

<%= Html.TextBoxFor(model => model.SomeDate,
    new Dictionary<string, object> { { "Value", Model.SomeDate.ToShortDateString() } })%>

Вы получаете привязку модели и можете переопределить свойство HTML «value» текстового поля форматированной последовательностью.

-121--1270965-

У меня есть идея - почему бы не попробовать альтернативную реализацию GC? .NET предоставляет три.

http://blogs.msdn.com/maoni/archive/2004/09/25/234273.aspx

Основываясь на вашем описании проблемы, я хотел бы узнать, как работает серверный GC для вас, поскольку он предоставляет отдельную кучу на ядро. Вероятно, также стоит посмотреть в фоновом режиме GC, который добавляет .NET 4.

http://blogs.msdn.com/maoni/archive/2008/11/19/so-what-s-new-in-the-clr-4-0-gc.aspx

Надеюсь, это немного полезнее для вашего конкретного случая, чем ответы до сих пор.

2
ответ дан 2 December 2019 в 21:02
поделиться

Параллельные задачи и даже необработанные потоки - это не чудодейственные средства для ускорения выполнения кода. Если у вас есть какие-либо блокировки, ресурсы или всего несколько ядер, вы можете замедлить код, пытаясь быть многопоточным. Вам также необходимо убедиться, что у вас нет подкачки контекста и, надеюсь, у вас более 4 ядер. (Не забывайте, что GC, CLR, Windows, а также другие приложения и службы борются за ресурсы / циклы.)

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

Библиотека параллельных задач была создана для общего использования. Если вам нужен высокооптимизированный код, вам может потребоваться также управлять своими собственными потоками. (В отличие от многих блогов, которые говорят ... в этой профессии нет волшебных пуль.)

Лучше всего будет создать экземпляр вашего рабочего класса для каждого потока, чтобы избежать построения и деконструкции на каждое действие. Ознакомьтесь с ThreadStaticAttribute . Насколько я понимаю, в .Net 4.0 есть и другие варианты, но у меня еще не было возможности поработать с ними.

0
ответ дан 2 December 2019 в 21:02
поделиться

При профилировании системы похоже, что из-за сборщика мусора происходит большая синхронизация потоков. Я занимаюсь распределением большого количества объектов, поэтому мне интересно, как я могу улучшить параллелизм, минимизируя переписывание моего кода.

Не выделяйте много объектов.Единственный универсальный способ ускорить ваш код - заставить его выполнять меньше работы. Если сборщик мусора занимает слишком много времени, есть два теоретических варианта:

  • реализовать лучший сборщик мусора или
  • дать сборщику мусора меньше работы

Первый пункт практически невозможен. Для замены .NET GC потребовалось бы много взлома, и потребуется много работы, чтобы спроектировать GC, который даже удаленно так же эффективен, как .NET.

Второй пункт - действительно ваш единственный вариант: если сборка мусора требует синхронизации, убедитесь, что происходит меньшее количество сборок. Обычно они возникают, когда куча gen0 слишком заполнена, чтобы удовлетворить запрос на выделение.

Так что убедитесь, что этого не происходит. Не выделяйте так много объектов. У вас есть несколько способов избежать этого:

  1. использование (выделенных в стеке) структур вместо классов может помочь снизить нагрузку на сборщик мусора. Особенно маленькие, недолговечные объекты, вероятно, выиграют от преобразования в структуры,
  2. Повторно используйте объекты, которые вы размещаете. Объекты с более длительным сроком существования перемещаются в кучу большего размера, где сборы происходят редко. Например, переместите выделения из циклов.
1
ответ дан 2 December 2019 в 21:02
поделиться
Другие вопросы по тегам:

Похожие вопросы: