0

我目前正在学习Clojure,并且我不确定如何使用STM来完成并发。我试图完成的任务非常简单,我有一个字符串向量,我想同时在每个字符串上运行一个函数,并用该函数返回的字符串替换该字符串。在Clojure中STM的并发性

我目前可以做到这一点很容易与PMAP:

(pmap function string_vector) 

我怎样才能做到用Clojure使用STM同样的事情?

+1

我已投票结束这个。这个问题没有得到很好的解决,因为它在线程协调领域没有任何要求,导致STM成为与解决方案有关的问题。它就像问我怎样才能用洗碗机吃苹果? –

回答

2

STM是一种跨线程共享数据的方式。如果你根本不需要进行协调(在这个例子中你不这样做),那么使用STM没有任何真正的理由。

+0

我明白了。我只是想知道学习的目的。我很难理解STM,任何帮助将不胜感激。 – Pythoner

+0

@Pythoner,仅仅因为它是为了“学习的目的”并不意味着它不应该是有道理的。你问的是如何说:“我有一架飞机,我怎么用它来学习驾驶(一辆汽车)?”当然,你可以沿高速公路滑行你的飞机。但是对于驾驶汽车实际上你并不聪明 - 它们是完全不同的机器,具有非常不同的预期用途,并且受到不同的控制。 –

1

clojure中的STM是关于随着时间的推移维持可变物的状态。这些状态每时每刻都在变化的事物被认为具有“身份”。正如你一生中拥有“你”的身份一样,即使三个月大的“你”在120岁时也不会承认“你”。所以让我们把东西可变在你的榜样,所以我们有借口使用STM:

让我们做一个公开提供可变的地方来存储字符串,然后平行改变他们那里:

user> (def current-strings (ref ["a" "b" "c"])) 
#'user/current-strings 
user> (dosync (alter current-strings (fn [the-string-at-this-instant] 
             (pmap #(.toUpperCase %) the-string-at-this-instant)))) 
("A" "B" "C") 
user> @current-strings 
("A" "B" "C") 
user> 

在这例如我们创建了一个事务,通过对其应用一个函数来改变我们字符串集合的状态。在内部,该函数恰好并行计算新值。

使这更有趣,让我们做的可变事情载体,然后在并行更新一堆独立可变的东西每个在它自己的事务:

user> (def current-strings [(ref "a") (ref "b") (ref "c")]) 
#'user/current-strings 

user> (doall 
     (pmap (fn [ref-to-update] 
       (dosync (alter ref-to-update #(.toUpperCase %)))) 
      current-strings)) 
("A" "B" "C") 

user> (map deref current-strings) 
("A" "B" "C") 
user> 

正如你所看到的,没有这需要STM,因为所有这些操作都可以用clojure中的其他可变类型处理,原子将是一个很好的选择。和裁判一起玩也很有趣!玩的开心!

+1

在这里要小心。既然pmap就像地图一样懒惰,你不应该仅仅为了副作用而对它进行评估,如果你想确保所有的结果都被实现了,那么就要强制整个事情。如果你没有碰巧在repl中打印这些变化,那么这些变化都不会保证发生(事实上,由于分块,只有前32个变化)。请注意https://gist.github.com/amalloy/906a65d5851ab61554b12482a8dbcb4a中的重复32。 – amalloy

+0

好点! “懒虫”在这里潜伏着。我在里面放了一个“doall”。还值得注意的是,如果你把dosync放在pmap之外,它不起作用。 –

+2

doall没有意义。你在一个字符串上调用doall,这是一个无操作。再次尝试使用超过32个元素的内容,而不将结果打印到repl中以查看是否正确。您需要完成pmap的结果,而不是其中的任何内容。 – amalloy