2010-08-27 2 views
10

В чем разница между Clojure STM (dosync) и синхронизацией Java с блоком?Clojure STM (dosync) x блок синхронизации Java

Im, читающий приведенный ниже код из проблемы «Спальный парикмахер». (http://www.bestinclass.dk/index.clj/2009/09/scala-vs-clojure-round-2-concurrency.html)

(defn the-shop [a] 
    (print "[k] entering shop" a) 
    (dosync  
    (if (< (count @queue) seats) 
     (alter queue conj a) 
     (print "[s] turning away customer" a)))) 

Чтобы избежать состояния гонки, используется dosync, поэтому я спрашиваю себя "Что такое различию (STM) с Java синхронизации блока"? Будет ли он блокировать этот критический код?

Заранее благодарен! Dantas

+0

Добро пожаловать. :-) –

+0

Привет, Михль, как и я ответил мне о STM отлично, позвольте мне спросить еще кое-что о clojure, что я не понимаю. Форма коммутирования. Предположим, что у меня есть 2 потока (t1 и t2). И идеология увеличивает ссылку, хорошо? t1 внутри dosync, получить значение ref - в транзакционном значении (0) - ... t2 получить контроль и смог увеличить значение от 0 до 1. t1 вернется и что он должен делать? wether t1 продолжает выполнение конечного результата не будет правильным. как коммутируют в этом случае? заранее спасибо – CHAPa

ответ

19

dosync и synchronized предоставляют доступ к совершенно различным абстракциям параллелизма.

synchronized - способ приобретения и освобождения замков. Когда поток входит в блок synchronized, он пытается получить соответствующую блокировку; если блокировка в настоящее время поддерживается другим потоком, текущий поток блокирует и ждет его освобождения. Это приводит к определенным проблемам, таким как риск тупика. Блокировка отпускается, когда нить покидает блок synchronized.

dosync отмечает блок кода, который должен быть запущен в транзакции. Транзакции в Clojure - это способ координации изменений в Ref (объекты, созданные с помощью функции ref); если вам нужен какой-то код для последовательного просмотра некоторых частей изменчивого состояния в Clojure - и, возможно, их изменение, вы помещаете их в Refs и выполняете свой код в транзакции.

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

Сделка не подвергается риску оказаться в тупике (если программист не собирается вводить тупик, не связанный с системой STM через Java-взаимодействие); livelock, с другой стороны, является определенной возможностью, хотя это не очень вероятно. В общем, многие - хотя и не все! - интуитивных программистов, связанных с транзакциями базы данных, действительны в контексте STM-систем, в том числе Clojure.

STM - это огромная тема; одним из превосходных ресурсов для изучения STM компании Clojure является статья Марка 0 Software Transactional Memory Марка Volkmann. Он углубляется в обсуждение STM Clojure в своих заключительных разделах, но начало может послужить отличным вводным чтением.

Что касается фрагмента, который вы цитировали, на самом деле это не то, что вы обычно хотели бы эмулировать в производственном коде, поскольку блоки dosync должны почти всегда быть свободными от побочных эффектов; print здесь могут быть полезны для демонстрации внутренней работы STM, но если вы хотите, чтобы транзакция вызывала побочные эффекты в реальном коде, вам нужно, чтобы она создала агента Clojure для этой цели (которая выполнила бы только свою задачу, если транзакция успешно совершает).

+0

Michal, u написал «с тех пор, как блоки dosync должны почти всегда быть свободными от побочных эффектов». консольная печать нарушит свойство «побочного эффекта»? поэтому обновление таблицы базы данных будет делать то же самое, все в порядке? Что предполагается внутри блока dosync? Еще раз спасибо, отличный пост! – CHAPa

+2

Правильно, распечатывая консоль и обновляя таблицу базы данных, можно квалифицировать как побочные эффекты. Блоки dosync вообще не должны содержать побочный код * кроме * вызовов для транзакционных Ref-modifying функций ('alter' /' commute'/'ref-set'), с важным исключением, что любые действия отправленные агентам, могут содержать побочные эффекты, которые должны произойти после завершения транзакции (все такие действия будут выполняться, если и когда совершается транзакция, поэтому нет риска вызвать один и тот же побочный эффект более одного раза). –

+1

Итак, если вам нужно изменить значения пары Refs и обновить вашу базу данных, ваш 'dosync' будет содержать вызовы' alter'/'commute' для изменения ссылок Refs и' send'/'send-off' Агент для выполнения обновления db после совершения транзакции (и, следовательно, больше не возникает риск повторной попытки или неудачи из-за достижения предела повтора). –

3

Также в дополнение к отличному ответу Michał, с транзакциями STM, читает, всегда вы получаете замороженное значение в начале транзакции и не должны ждать завершения текущей транзакции.

+0

Да! Операции чтения не требуют блокировки. он заблокирован. когда вы читаете, u получите снимок. Но если вы пишете, операция выполняется только в том случае, если моментальный снимок равен тому, что у вас есть. если при попытке записи данных данные не совпадают, откат операции. – CHAPa

3

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

(locking x & body) 
0

Основное отличие заключается в следующем

Clojure STM поддерживает оптимистичный параллелизм, тогда как JAVA синхронизированы является пессимистом

Clojure СТМ не приобретает блокировку, пока не более чем один поток. если изменяемое состояние обновляется другим потоком, то повторяется операция внутри dosync. Кроме того, dosync является обязательным для изменяемых состояний. Clojure выдает исключение anticState, когда dosync отсутствует, в отличие от JAVA.

Смежные вопросы