Как использовать ссылку на временную переменную в Clojure потокобезопасным способом? - PullRequest
0 голосов
/ 28 ноября 2018

У меня есть функция синтаксического анализа, которая анализирует программу из файла и «компилирует» ее в список функций Clojure и ссылку на карту переходных процессов.Язык представляет собой простой DSL с изменяемыми переменными (A = A + 1).После компиляции я хочу иметь возможность вызывать список функций Clojure с некоторыми новыми данными и получать разные значения для изменяемых переменных.Поскольку я использую карту переходных процессов, для хранения и изменения изменяемых переменных код не является поточно-ориентированным.Как это исправить?Есть ли способ реализовать эту функцию без переходных коллекций?

В приведенном ниже коде файл script анализируется и генерирует карту prog.Функции находятся в :list и выполняются функцией ev.Я изменяю runtime переходные переменные между запусками.

(defn read-script [script]
  (try
    (let [runtime (transient {:vars {:var1 20 :var2 ""}})
          prog    (parse (slurp script) runtime)]
      (run! ev (:list prog)) ; Calls the functions
      (println runtime) ; Show vars
      (assoc! runtime :vars {:var1 78}) ; Initialize vars
      (run! ev (:list prog))
      (println runtime prog) ; Show new vars
      ... )))

Ответы [ 2 ]

0 голосов
/ 04 декабря 2018

Я надеялся получить лучший ответ, но это то, чем я в конечном итоге воспользовался.Мой код использует Vars .Vars предоставляют механизм ссылки на изменяемое хранилище, которое можно динамически восстанавливать (к новому хранилищу) для каждого потока, используя binding.Это код:

(def ^:dynamic runtime ())

(defn run-prog [prog runtime-init]
  (binding [runtime (transient runtime-init)] ;bind the new runtime
    (run! ev (:list prog))  ; Calls the functions
    (persistent! runtime)))

(defn read-script [script]
  (try
    (let [prog (parse (slurp script))]
      (println (run-prog prog {:vars {:var1 20 :var2 ""}}))  ; Show vars
      (println (run-prog prog {:vars {:var1 78}}))  ; Show vars
       ... )))  

run-prog вызывается с проанализированной программой (список вызовов функций) и начальным значением для переменных.Он возвращает конечное состояние переменных и является потокобезопасным (каждый поток имеет доступ только к своей собственной карте переменных).

Если вы не хотите использовать временные коллекции, вы можете использовать set! чтобы изменить всю карту переменных на новое значение.

0 голосов
/ 28 ноября 2018

Канонические потокобезопасные, изменчивые, несогласованные объекты - это атомы.Вместо этого просто используйте атомы.

Переходные процессы не только не поточнобезопасны, они должны использоваться , как если бы они на самом деле были неизменными;например: вы не можете полагаться на побочный эффект assoc! на переходной карте, как здесь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...