Как только ваши глобальные данные могут быть обновлены.вы нарушаете чистую функциональную парадигму.В этом смысле вам нужна какая-то императивная структура.Тем не менее, это достаточно важно, чтобы большинство функциональных языков предлагали способ сделать это, и вам нужно, чтобы он в любом случае мог общаться с остальным миром.(Самым сложным формальным является монада IO
в Haskell.) Помимо простых привязок для некоторой другой библиотеки синхронизации, они, возможно, попытались бы реализовать структуру данных без блокировки и без ожидания, если это возможно.
Некоторые подходы включают:
- К данным, которые записываются только один раз и никогда не изменяются, можно безопасно получить доступ без блокировок или ожидания на большинстве процессоров.(Обычно существует инструкция ограничения памяти, чтобы гарантировать, что память обновляется в правильном порядке как для производителя, так и для потребителя.)
- Некоторые структуры данных, такие как список различий, имеют свойство, которое можно использоватьна обновления без аннулирования каких-либо существующих данных.Допустим, у вас есть список ассоциаций
[(1,'a'), (2,'b'), (3,'c')]
, и вы хотите обновить его, изменив третью запись на 'g'
.Если вы выражаете это как (3,'g'):originalList
, то вы можете обновить текущий список новой версией и оставить originalList
действительным и неизменным.Любой поток, который видел его, все еще может безопасно использовать его. - Даже если вам придется работать с сборщиком мусора, каждый поток может сделать свою собственную локальную для потока копию общего состояния, пока оригинал не получитудаляется во время копирования.Базовая низкоуровневая реализация будет представлять собой модель производителя / потребителя, которая атомарно обновляет указатель на данные состояния и вставляет инструкции ограничения памяти перед операциями обновления и копирования.
- Если в программе есть способ сравнения-и поменяйте местами атомарно, и сборщик мусора знает, что каждый поток может использовать шаблон получения-копирования-обновления.Сборщик мусора с поддержкой потоков будет хранить старые данные до тех пор, пока их использует любой поток, и перерабатывать их, когда последний поток завершит работу с ними.Это не должно требовать блокировки в программном обеспечении (например, в современных ISA увеличение или уменьшение счетчика размера слова является атомарной операцией, а атомарное сравнение-и-замена не требует ожидания).
- Функциональный языкМожно добавить расширение для вызова библиотеки IPC, написанной на другом языке, и обновить данные на месте.В Haskell это было бы определено с помощью монады
IO
для обеспечения последовательной согласованности памяти, но почти каждый функциональный язык имеет некоторый способ обмена данными с системными библиотеками.
Итак, функциональный язык делаетпредложить некоторые гарантии, которые полезны для эффективного параллельного программирования.Например, большинство современных ISA не накладывают лишних накладных расходов на несколько потоков считывателей, когда имеется не более одного записывающего устройства, не могут возникать определенные ошибки согласованности, и функциональные языки хорошо подходят для выражения этого шаблона.