我有一个解析器功能,可以从文件中解析程序并将其“编译”为Clojure函数的列表以及对瞬态映射的引用。该语言是具有可变变量(A = A + 1)的简单DSL。编译后,我希望能够使用一些新数据调用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
... )))
答案 0 :(得分:4)
规范的线程安全,可变,不协调的对象是原子。只需使用原子即可。
瞬态不仅不是线程安全的,还必须像实际上是不可变的那样使用 ;例如:您不能像在此那样依赖瞬态图上assoc!
的副作用。
答案 1 :(得分:0)
我希望得到一个更好的答案,但这就是我最终使用的答案。我的代码使用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!
将整个变量映射更改为新值。