Чем параллельные языки для передачи сообщений на практике лучше, чем параллельные языки с общей памятью на практике? - PullRequest
37 голосов
/ 01 ноября 2011

Я был Java-разработчиком много лет, но никогда не сталкивался с проблемами параллелизма, пока не начал заниматься разработкой для Android и внезапно обнаружил, что «приложение не отвечает» и очевидные тупиковые ситуации.

Это заставило меня понять, как трудно понять и устранить некоторые из этих проблем параллелизма. Как новые языки, такие как Scala и Go, улучшают параллелизм? Как они более понятны и как они предотвращают ошибки параллелизма? Может ли кто-нибудь привести примеры из реальной жизни, демонстрирующие преимущества?

Ответы [ 4 ]

48 голосов
/ 01 ноября 2011

Три основных претендента на упрощение параллелизма - акторы, программная транзакционная память (STM) и автоматическое распараллеливание. Scala имеет реализации всех трех.

Актеры

Актеры находят свою наиболее заметную реализацию в языке Erlang, который, насколько я знаю, где и началась идея *. Эрланг разработан с нуля вокруг актеров. Идея состоит в том, что сами актеры являются черными ящиками друг для друга; они взаимодействуют только путем передачи сообщений.

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

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

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

Программная транзакционная память

STM основан на идее, что наиболее важной параллельной операцией является получение некоторого общего состояния, манипулирование им и запись его обратно. Так что это дает возможность сделать это; однако, если он сталкивается с какой-то проблемой - которую он обычно задерживает на обнаружение до самого конца, в этот момент он проверяет, что все записи выполнены правильно - он откатывает изменения и возвращает ошибку (или пытается снова).

Это и высокопроизводительный (в ситуациях только с умеренной конкуренцией, поскольку обычно все идет просто отлично) и устойчивый к большинству видов ошибок блокировки , поскольку система STM может обнаруживать проблемы (и даже потенциально делать такие вещи, как убрать доступ из запроса с более низким приоритетом и передать его более высокому приоритету).

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

Scala имеет библиотеку STM, которая не является частью стандартной библиотеки, но рассматривается для включения. Clojure и Haskell имеют хорошо разработанные библиотеки STM.

Автоматическое распараллеливание

Автоматическое распараллеливание предполагает, что вы не хотите думать о параллелизме; Вы просто хотите, чтобы все произошло быстро. Поэтому, если у вас есть какая-то параллельная операция - например, применение какой-либо сложной операции к коллекции элементов, по одному, и создание некоторой другой коллекции в результате - у вас должны быть подпрограммы, которые автоматически делают это параллельно. Коллекции Scala можно использовать таким образом (существует метод .par, который преобразует обычную последовательную коллекцию в ее параллельный аналог). Многие другие языки имеют аналогичные функции (Clojure, Matlab и т. Д.).


Редактировать: На самом деле, модель Actor была описана еще в 1973 году и, вероятно, была мотивирована более ранней работой в Simula 67 (с использованием сопрограмм вместо параллелизма); в 1978 году появились связанные последовательные процессы . Таким образом, возможности Эрланга не были уникальными в то время, но язык был уникально эффективен при развертывании модели актера.

6 голосов
/ 01 ноября 2011

В идиоматической программе Go потоки сообщают о состоянии и данных по каналам. Это может быть сделано без необходимости в замках. Передача данных по каналу получателю подразумевает передачу права собственности на данные. После того, как вы отправили значение через канал, вам больше не нужно работать с ним, поскольку тот, кто получил его, теперь «владеет» им.

Однако следует отметить, что эта передача «владения» никоим образом не принудительно применяется средой выполнения Go. Объекты, отправляемые по каналам, не помечаются и не помечаются или что-либо подобное Это просто соглашение. Таким образом, если вы склонны, вы можете выстрелить себе в ногу, изменив значение, которое вы ранее отправляли по каналу.

Сила Go заключается в том, что синтаксис Go, предлагаемый (запуск процедур и работа каналов), значительно упрощает написание кода, который функционирует правильно, и, таким образом, предотвращает состояние гонки и мертвые блокировки. Четкая механика параллелизма Go позволяет легко рассуждать о том, что произойдет в вашей программе.

В качестве примечания: стандартная библиотека в Go по-прежнему предлагает традиционные мьютексы и семафоры, если вы действительно хотите их использовать. Но вы, очевидно, делаете это на свое усмотрение и на свой страх и риск.

6 голосов
/ 01 ноября 2011

Для меня использование акторов Scala (Akka) имело несколько преимуществ по сравнению с традиционными моделями параллелизма:

  1. Использование системы передачи сообщений, такой как актеры, позволяет легко управлять общим состоянием. Например, я часто буду оборачивать изменяемую структуру данных в актере, поэтому единственный способ получить к ней доступ - это передача сообщений. Поскольку субъекты всегда обрабатывают одно сообщение за раз, это гарантирует, что все операции с данными являются поточно-ориентированными.
  2. Актеры частично устраняют необходимость иметь дело с порождением и поддержанием потоков. Большинство библиотек актеров справляются с распределением актеров по потокам, поэтому вам нужно только беспокоиться о запуске и остановке актеров. Часто я создаю серию идентичных действующих лиц, по одному на физическое ядро ​​ЦП, и использую субъект балансировки нагрузки для равномерного распределения им сообщений.
  3. Актеры могут помочь повысить надежность системы. Я использую актеров Akka, и одна из них заключается в том, что вы можете создать супервизор для актеров, где в случае сбоя актера супервизор автоматически создаст новый экземпляр. это может помочь предотвратить ситуации с многопоточностью, когда поток падает, и вы застряли с наполовину запущенной программой. Также очень легко раскручивать новых актеров по мере необходимости и работать с удаленными актерами, работающими в другом приложении.

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

0 голосов
/ 01 ноября 2011

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

...