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

редактировать

В информатике, программное обеспечение транзакционная память (STM ) является механизмом управления параллелизмом, аналогичным транзакциям базы данных для управления доступом к разделяемой памяти в параллельных вычислениях. Это альтернатива синхронизации на основе блокировки. STM - это стратегия, реализованная в программном обеспечении, а не в качестве аппаратного компонента. Транзакция в этом контексте происходит, когда часть кода выполняет серию операций чтения и записи в общую память. Эти операции чтения и записи логически происходят в один момент времени; промежуточные состояния не видны другим (успешным) транзакциям. Идея аппаратной поддержки транзакций возникла в статье 1986 года Тома Найта. Идею популяризировали Морис Херлихи и Дж. Элиот Б. Мосс. В 1995 году Нир Шавит и Дэн Туиту распространили эту идею на программную транзакционную память (STM). С 2005 года STM находится в центре интенсивных исследований, и поддержка практических внедрений растет.

Содержание

  • 1 Производительность
  • 2 Концептуальные преимущества и недостатки
  • 3 Составные операции
  • 4 Предлагаемая языковая поддержка
  • 5 Транзакционная блокировка
  • 6 Проблемы реализации
  • 7 Реализации
    • 7.1 C / C ++
    • 7.2 C #
    • 7.3 Clojure
    • 7.4 Common Lisp
    • 7.5 Erlang
    • 7.6 F #
    • 7.7 Groovy
    • 7.8 Haskell
    • 7.9 Java
    • 7.10 JavaScript
    • 7.11 OCaml
    • 7.12 Perl
    • 7.13 Python
    • 7.14 Ruby
    • 7.15 Scala
    • 7.16 Smalltalk
    • 7.17 Другие языки
  • 8 Ссылки
  • 9 Внешние ссылки

Производительность

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

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

Однако на практике системы STM также страдают от снижения производительности по сравнению с системами на основе мелкозернистых блокировок на небольшом количестве процессоров (от 1 до 4 в зависимости от приложения). Это связано в первую очередь с накладными расходами, связанными с ведением журнала, и временем, затраченным на фиксацию транзакций. Даже в этом случае производительность обычно не хуже, чем вдвое. Сторонники STM считают, что это наказание оправдано концептуальными преимуществами STM.

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

Концептуальные преимущества и недостатки

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

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

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

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

Составные операции

В 2005 году Саймон Марлоу, Саймон Пейтон Джонс и Морис Херлихи описали построенную систему STM на Concurrent Haskell, который позволяет объединять произвольные атомарные операции в более крупные атомарные операции - полезная концепция, невозможная при программировании на основе блокировок. Процитируем авторов:

Возможно, наиболее фундаментальное возражение [...] состоит в том, что программы, основанные на блокировках, не составляют: правильные фрагменты могут не работать при объединении. Например, рассмотрим хеш-таблицу с поточно-безопасными операциями вставки и удаления. Теперь предположим, что мы хотим удалить один элемент A из таблицы t1 и вставить его в таблицу t2; но промежуточное состояние (в котором ни одна таблица не содержит элемента) не должно быть видно другим потокам. Если разработчик хэш-таблицы не предвидит эту потребность, нет никакого способа удовлетворить это требование. [...] Короче говоря, операции, которые являются правильными по отдельности (вставка, удаление), не могут быть объединены в более крупные правильные операции.. - Тим Харрис и др., «Транзакции составной памяти», Раздел 2: Предпосылки, стр. 2

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

Авторы также предложили механизм композиции альтернатив, функцию илиElse . Он запускает одну транзакцию и, если эта транзакция повторяет попытку, запускает вторую. Если оба повторяют попытку, он пробует их снова, как только будет внесено соответствующее изменение. Это средство, сравнимое с такими функциями, как вызов POSIX network select (), позволяет вызывающему абоненту ожидать одновременно любого из нескольких событий. Он также упрощает программные интерфейсы, например, предоставляя простой механизм для преобразования между блокирующими и неблокирующими операциями.

Эта схема была реализована в компиляторе Glasgow Haskell.

Предлагаемая языковая поддержка

Концептуальная простота STM позволяет представить их программисту с использованием относительно простого синтаксиса языка. В работе Тима Харриса и Кейра Фрейзера «Языковая поддержка облегченных транзакций» была предложена идея использования классической условной критической области (CCR) для представления транзакций. В своей простейшей форме это просто «атомарный блок», блок кода, который логически возникает в один момент:

// Вставляем узел в двусвязный список атомарно атомарно {newNode->prev = узел; newNode->следующий = узел->следующий; узел->следующий->предыдущий = новый узел; узел->следующий = новый узел; }

Когда достигается конец блока, транзакция фиксируется, если возможно, или прерывается и повторяется. (Это просто концептуальный пример, а не правильный код. Например, он ведет себя некорректно, если узел удаляется из списка во время транзакции.)

CCR также допускают условие защиты, которое позволяет транзакции ждать, пока у него есть работа:

atomic (queueSize>0) {удалить элемент из очереди и использовать его}

Если условие не выполняется, диспетчер транзакций будет ждать, пока не будет выполнена другая транзакция фиксация, которая влияет на условие перед повторной попыткой. Эта слабая связь между производителями и потребителями повышает модульность по сравнению с явной передачей сигналов между потоками. «Транзакции составной памяти» пошли дальше с помощью команды retry (обсужденной выше), которая может в любой момент прервать транзакцию и дождаться, пока какое-то значение, ранее считанное транзакцией, не изменится, прежде чем повторять попытку. Например:

atomic {if (queueSize>0) {удалить элемент из очереди и использовать его} else {retry }}

Эта возможность динамически повторять попытку в конце транзакция упрощает модель программирования и открывает новые возможности.

Одна из проблем заключается в том, как ведут себя исключения, когда они распространяются вне транзакций. В «Транзакции составной памяти» авторы решили, что это должно прервать транзакцию, поскольку исключения обычно указывают на неожиданные ошибки в Concurrent Haskell, но что исключение может сохранить информацию, выделенную и прочитанную во время транзакции, для диагностических целей. Они подчеркивают, что другие проектные решения могут быть разумными в других условиях.

Транзакционная блокировка

STM может быть реализован как алгоритм без блокировки или может использовать блокировку. Существует два типа схем блокировки: при блокировке по времени (Ennals, Saha и Harris) запись в память выполняется путем временного получения блокировки для данного местоположения, непосредственной записи значения и регистрации его в журнале отмены. Блокировка во время фиксации блокирует участки памяти только на этапе фиксации.

Схема времени фиксации, названная «Transactional Locking II», реализованная Дайсом, Шалевым и Шавитом, использует часы глобальной версии. Каждая транзакция начинается с чтения текущего значения часов и сохранения его как версии для чтения. Затем при каждом чтении или записи версия определенной области памяти сравнивается с версией чтения; и, если он больше, транзакция прерывается. Это гарантирует, что код выполняется на согласованном снимке памяти. Во время фиксации все места записи блокируются, а номера версий всех мест чтения и записи повторно проверяются. Наконец, глобальные часы версии увеличиваются, новые значения записи из журнала записываются обратно в память и маркируются новой версией часов.

Все более широко используемым методом управления конфликтами транзакций в транзакционной памяти, и особенно в STM, является упорядочение фиксации (также называемое упорядочением фиксации; CO). Он используется для оптимистического достижения сериализуемости (т.е. без блокировки в случае конфликта и только блокировки для фиксации) с помощью «порядка фиксации» (например, Ramadan et al. 2009 и Zhang et al. 2006). Сериализуемость - это основа корректности (параллельных транзакций и) транзакционной памяти. Уже опубликованы десятки статей STM о «порядке фиксации», и этот метод защищен рядом патентов.

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

Проблемы реализации

Одна из проблем при реализации программной транзакционной памяти с оптимистичным чтением заключается в том, что неполная транзакция может считывать несогласованное состояние (то есть читать смесь старых и новых значений написано другой транзакцией). Такая транзакция обречена на прерывание, если она когда-либо попытается выполнить фиксацию, поэтому это не нарушает условие согласованности, обеспечиваемое транзакционной системой, но это «временное» несовместимое состояние может привести к тому, что транзакция вызовет фатальное исключительное состояние, такое как как ошибку сегментации или даже зайти в бесконечный цикл, как в следующем надуманном примере из рисунка 4 «Поддержка языков для облегченных транзакций»:

atomic {if (x! = y) while (true) {} }
атомарный {x ++; y ++; }
Транзакция A
Транзакция B

Если изначально x = y, ни одна из вышеуказанных транзакций не изменяет этот инвариант, но возможно, что транзакция A прочитает x после того, как транзакция B обновит его, но прочитает y до того, как транзакция B обновит его, заставляя его войти в бесконечный цикл. Обычная стратегия решения этой проблемы - перехват любых фатальных исключений и прерывание любой недопустимой транзакции.

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

Реализации

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

C / C ++

  • TinySTM STM на основе времени и Tanger для интеграции STM с C и C ++ через LLVM.
  • The Облегченная библиотека транзакций (LibLTX), реализация C Роберта Энналса, ориентированная на эффективность и основанная на его статьях «Программная транзакционная память не должна быть свободной от препятствий» и «Программная транзакционная память, чувствительная к кеш-памяти».
  • LibCMT, реализация с открытым исходным кодом на языке C от Duilio Protti на основе «Composable Memory Transactions». Реализация также включает привязку C #.
  • TARIFA - это прототип, который переносит ключевое слово "atomic" в C / C ++ путем инструментального вывода компилятора на ассемблер.
  • Intel STM Compiler Prototype Edition реализует STM для C / C ++ непосредственно в компиляторе (компиляторе Intel) для Linux или Windows, создавая 32- или 64-разрядный код для процессоров Intel или AMD. Реализует атомарное ключевое слово, а также предоставляет способы украшения определений функций (declspec) для управления / авторизации использования в атомарных разделах. Существенная реализация в компиляторе с заявленной целью, позволяющая проводить крупномасштабные эксперименты в программе C / C ++ любого размера. Intel выпустила четыре исследовательских релиза этой специальной экспериментальной версии своего компилятора продукта.
  • stmmap Реализация STM на C, основанная на отображении разделяемой памяти. Он предназначен для разделения памяти между потоками и / или процессами (а не только между потоками внутри процесса) с транзакционной семантикой. Многопоточная версия его распределителя памяти находится на C ++.
  • CTL Реализация STM на C, основанная на TL2, но со многими расширениями и оптимизациями.
  • STM на основе TL2 от исследовательская группа Scalable Synchronization в Sun Microsystems Laboratories, как показано в статье DISC 2006 «Transactional Locking II».
  • Несколько реализаций Тима Харриса и Кейра Фрейзера, основанные на идеях из его статей «Поддержка языков для облегченных транзакций», «Практическая свобода от блокировок» и готовящаяся к выходу неопубликованная работа.
  • RSTM The University of Rochester STM, написанная группой исследователей под руководством Майкла Л. Скотт.
  • G ++ 4.7 теперь поддерживает STM для C / C ++ непосредственно в компиляторе. Эта функция по-прежнему указана как «экспериментальная», но может по-прежнему обеспечивать необходимую функциональность для тестирования.
  • STM является частью платформы транзакций picotm для C

C #

  • Shielded Строгий и в основном STM для.NET без препятствий, написанный на C #. Возможности включают: условные транзакции, коммутируемые (с низким уровнем конфликтов) операции, типы транзакционных сборов и автоматическое создание транзакционных прокси-подклассов для объектов POCO.
  • STMNet Чистый C #, открытый, легкий программный API транзакционной памяти с открытым исходным кодом.
  • SXM, реализация транзакций для C # от Microsoft Research. Документация, Страница загрузки Снято с производства.
  • LibCMT, реализация с открытым исходным кодом на C от Duilio Protti на основе «Транзакций составной памяти». Реализация также включает привязку C #.
  • NSTM, программную транзакционную память.NET, полностью написанную на C #, предлагающую действительно вложенные транзакции и даже интеграцию с System.Transactions.
  • MikroKosmos Ориентированный на проверку Реализация модели STM на C #.
  • ObjectFabric см. Реализации Java.
  • Sasa.TM Реализация программной транзакционной памяти на чистом C #.

Clojure

  • Clojure имеет поддержку STM, встроенную в базовый язык

Common Lisp

  • CL- STM Многоплатформенная реализация STM для Common Lisp.
  • STMX Активно поддерживаемая библиотека параллелизма с открытым исходным кодом, предоставляющая программное обеспечение, оборудование и транзакции гибридной памяти для Common Lisp.

Erlang

  • Mnesia Распределенная транзакционная СУБД в памяти, встроенная в Erlang / OTP, которая выполняет роль STM; Возможно, самая старая реализация STM в дикой природе.

F #

  • F # имеет их через [1] FSharpX - образец в [2] F#

Groovy

  • GPars - Структура Gpars содержит поддержку STM с использованием реализации Java Multiverse.

Haskell

Java

  • Исследования SCAT group реализует AtomJava.
  • JVSTM реализует концепцию Versioned Boxes, предложенную João Cachopo и António Rito Silva, членами Software Engineering Group - INESC- ID. Начиная с версии 2.0, JVSTM полностью свободен от блокировок.
  • Deuce Среда выполнения для программной транзакционной памяти Java, использующая манипуляции с байтовым кодом.
  • Multiverse Является программной транзакционной памятью на основе Java 1.6+ (STM), которая использует Multi Version Concurrency Control (MVCC) в качестве механизма управления параллелизмом.
  • DSTM2 Библиотека динамической программной транзакционной памяти Sun Lab
  • ObjectFabric - это реализация с открытым исходным кодом для Java. и.NET. Его можно превратить в распределенный STM с помощью механизма расширения. Другие расширения позволяют вести журнал, уведомлять об изменениях и сохранять.
  • ScalaSTM - STM на основе библиотеки, написанный на Scala, который дополнительно предоставляет ориентированный на Java API, позволяющий использовать с объектами Runnable и Callable.

JavaScript

  • AtomizeJS реализует распределенную программную транзакционную память для веб-браузеров с помощью одного сервера NodeJS для проверки результатов транзакций.

OCaml

  • coThreads, библиотека параллельного программирования для OCaml, предлагает STM (первоначально STMLib ) в качестве модуля. Как и любые другие компоненты в этой библиотеке, модуль STM может использоваться единообразно с потоками уровня VM, системными потоками и процессами.

Perl

Python

Ruby

  • MagLev - это реализация интерпретатора Ruby, построенная на основе GemStone / S виртуальная машина
  • Concurrent Ruby - это библиотека, обеспечивающая параллельные функции для Ruby, включая STM

Scala

  • ScalaSTM - черновик предложения вместе с эталонной реализацией CCSTM для включения в стандартную библиотеку Scala
  • Akka STM - Структура Akka содержит поддержку STM как в Scala, так и в Java
  • MUTS - Транзакции Манчестерского университета для Scala
  • ZIO - Реализация в ZIO вдохновлен STM API в Haskell.
  • Cats STM - расширение Cats Effect с программной реализацией транзакционной памяти, аналогичной той, что используется в пакете Haskell stm.

Smalltalk

  • GemStone / S [3] Сервер объектов транзакционной памяти для Smalltalk.
  • STM для Smalltalk с открытым исходным кодом (лицензия MIT) Pharo

Другое languages ​​

  • Fortress - это язык, разработанный Sun, который использует DSTM 2
  • STM.NET

Ссылки

Внешние ссылки

Последняя правка сделана 2021-06-08 08:28:13
Содержание доступно по лицензии CC BY-SA 3.0 (если не указано иное).
Обратная связь: support@alphapedia.ru
Соглашение
О проекте