Досинхронизация Clojure внутри будущего против будущего внутри досинхронизации

У меня есть следующий фрагмент кода

(def number (ref 0))

(dosync (future (alter number inc)))  ; A
(future (dosync (alter number inc)))  ; B

Второй успешно, но первый терпит неудачу с no transaction is running. Но он завернут в досинк, верно?

Запоминает ли clojure открытие транзакций в зависимости от того, в каком потоке он был создан?


person Faiz Halde    schedule 07.11.2017    source источник


Ответы (2)


Ты прав. Вся цель dosync состоит в том, чтобы начать транзакцию в текущем потоке. future запускает свой код в новом потоке, поэтому alter в случае, если A не находится внутри dosync для своего потока.

Для случая B alter и dosync находятся в одном и том же (новом) потоке, поэтому проблем нет.

person Alan Thompson    schedule 07.11.2017

Есть несколько причин, по которым это не работает. Как пишет Алан Томпсон, транзакции размещаются в одном потоке, поэтому при создании нового потока вы теряете свою транзакцию.

Другой проблемой является динамическая область действия dosync. Та же проблема возникла бы, если бы вы написали

((dosync #(alter number inc)))

Здесь мы создаем функцию внутри области dosync, и пусть эта функция будет результатом dosync. Затем мы вызываем функцию из-за пределов блока dosync, но, конечно, транзакция больше не выполняется.

Это очень похоже на то, что вы делаете с future: future создает функцию, а затем выполняет ее в новом потоке, возвращая дескриптор, который вы можете использовать для проверки хода выполнения этого потока. Даже если бы межпоточные транзакции были разрешены, здесь возникло бы состояние гонки: блок dosync закрывает свою транзакцию до или после выполнения вызова alter в future?

person amalloy    schedule 07.11.2017