Состояние гонки в Clojure stm?

Здравствуйте, я читал книгу Joy of clojure, и в разделе о STM у них есть изображение двух транзакций, где A изначально получает то же значение из ссылки, что и B, а затем обе транзакции A и B выполняют свои вычисления, но завершает A сначала и делает фиксацию переменной, поэтому B должен повторить попытку.

Но я думаю о том, если бы B повторил попытку с фиксацией A. А если это так, то что, если все наоборот? Тогда конечное значение будет существенно отличаться.

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


person Tobias    schedule 01.02.2015    source источник


Ответы (1)


Давайте посмотрим на пример:

(defn test-trans []
  (let [x (ref 1)
        t-inc #(dosync (alter x inc))
        t-mul #(dosync (alter x (partial * 2)))
        fns (flatten (repeat 10 [t-mul t-inc]))]
    (last (pmap (fn [f] (f)) fns))
    @x))

Здесь у нас есть 2 транзакционные функции — увеличить x на 1 и умножить x на 2. Мы применяем 20 таких функций (по 10 каждого вида) параллельно и наблюдаем конечное значение ref. Действительно, результаты разные для каждого запуска:

=> (test-trans)
2418
=> (test-trans)
2380
=> (test-trans)
1804
=> (test-trans)
4210

На самом деле это правильное поведение. STM гарантирует, что код будет выполняться без блокировок, а изменения применяются атомарно (они не могут быть применены только частично). Однако это не гарантирует, что мы получим одинаковый результат для разного порядка транзакций.

Clojure предоставляет отличные инструменты параллельного программирования, которые значительно упрощают написание правильного кода. Но избегание таких условий гонки является обязанностью разработчика (на самом деле, такие случаи являются явным признаком плохого дизайна системы).

Другой пример из SQL:

DELETE FROM tbl WHERE col=1
UPDATE tbl SET col=2 WHERE col=1

Если эти запросы выполнять параллельно, то какой бы уровень изоляции ни использовался для транзакций - результат будет зависеть от порядка.

person Jarlax    schedule 01.02.2015