Изменяемый и неизменяемый для параллельных приложений [закрыто]

StackOverflow https://stackoverflow.com/questions/889804

Вопрос

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

Вы можете использовать блокировки с изменяемыми объектами, верно?Чем он отличается от других методов, используемых с неизменяемыми типами в параллельных приложениях?

Вы, по крайней мере, отказались от использования блокировок с неизменяемыми типами, верно?

Это было полезно?

Решение

Типы

  • Используйте неизменяемые типы как можно чаще.
  • Максимально используйте потокобезопасные коллекции вместо явных блокировок.
  • Используйте изменяемые типы только тогда, когда у вас нет другого разумного выбора.

Потоки

  • Используйте пулы потоков как можно чаще.
  • Используйте бесконечные циклы, когда пулы потоков невозможны.
  • В крайнем случае запускайте и останавливайте потоки вручную.

Если вам все же необходимо использовать явные блокировки, тщательно задокументируйте их.Особенно, когда дело касается порядка блокировки объектов.Если вы знаете, что объекты Foo всегда блокируются раньше объектов Bar и что Foo(ключ 100) всегда блокируется раньше Foo(ключ = 200), взаимоблокировок не будет.

Другие советы

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

Изменяемость не влияет на блокировку.

Когда вы используете изменяемые типы, вы подвергаете себя ошибкам Write-After-Read или Write-After-Write.Это ошибки синхронизации, связанные с обновлением значения, в то время как другие потоки одновременно читают или обновляют это значение.

Чтобы предотвратить ошибки синхронизации, вы должны использовать какой-либо механизм блокировки.Если вы используете явную блокировку, вам нужно быть очень осторожным с порядком получения блокировок.Если вы не будете осторожны, вы можете создать взаимоблокировки.Например:Поток A получает блокировку X, затем поток B получает блокировку Y.Некоторое время спустя поток A запрашивает блокировку Y, а поток B запрашивает блокировку X.Это заставляет оба потока бесконечно ждать блокировок, которые никогда не будут сняты.

Два хороших практических правила блокировки:

  • Получите блокировки в определенном порядке (например.всегда приобретайте Lock X перед Lock Y)
  • Удерживайте замки как можно более короткое время.Приобретайте их, когда они вам понадобятся, и отпускайте их, как только закончите с ними.

Если вы никогда не записываете данные в объект после его создания, вам не нужно блокировать его перед доступом к нему.Таким образом, вам не нужно будет блокировать неизменяемые объекты.

По возможности используйте неизменяемые типы.Используйте изменяемые типы, когда это необходимо (сериализация и т. д.).

Используйте System.Threading.Tasks для всей вашей распараллеливания — задачи будут даже встроены в язык C# 5, когда будут добавлены ключевые слова async и await.

Я написал статью об изменяемых/неизменяемых типах в C#: http://rickyhelgesson.wordpress.com/2012/07/17/mutable-or-immutable-in-a-parallel-world/

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top