2024 Clojure状态调查中分享您的看法!

欢迎!有关该功能的更多信息,请参阅关于页面。

0
引用、代理、原子

我了解一点Lisp,但Clojure感觉有点不同

(defn mojorate []
  (let [v (vec (range 1 11))
        max (- (count v) 1)
        atomix (atom [])
        chanl (async/chan)]
    (println v)
    (loop [i 0]
      (async/go
        (>! chanl (swap! atomix conj (/ (get v i) 2))))
      (if (= i max)
        (do (<!! (async/go (<! chanl)))
          (async/close! chanl)
          @atomix)
        (recur (inc i))))))

这只是关于channel,atom,loop/recur等的练习。

你能这样做吗?

不太清楚你到底在问什么 - 你能否详细说明?
它按预期工作了,但我不确定这是否是1.:惯用的2.:最佳实践3.:或者有更好的做法。
"预期的"是什么意思?函数 supposed 做了什么?运行时,我在不同的运行中看到不同的结果,所以我无法确切知道你实际上需要什么。
by
我总是得到
testomato.core> (mojorate)
[1 2 3 4 5 6 7 8 9 10]                                                                      
[1/2 1 3/2 2 5/2 3 7/2 9/2 5]

这段代码将10个数字发送到通道,并返回它们的一半。

1 个回答

+1
by

你有很多go块,不仅是指代码中的数量,还包括执行的数量。循环中的第一个go块不阻塞——它立即允许执行继续。不能保证在相同的块再次执行之前,前面的块有足够的时间将值放入通道。这是一个竞态条件。

为了确认,只需运行此代码:(set (repeatedly 10000 mojorate))。如果所有你得到的是一个只有一个元素的集合,请增加该数字。

这段代码将10个数字发送到通道,并返回它们的一半。

句子的前半部分是函数用户的实施细节,并且与函数用户无关。如果你只需要做的是从一个分之一的1开始获取10个数字的向量,那么它是当然的(mapv #(/ % 2) (range 1 11))

如果你需要其他东西,请详细描述,这样我们就不会陷入XY问题。原始函数可以用多种方式改写——如果你的实际问题有特定要求,那么这些改写都可能不正确。

by
我试图熟悉这个概念。并且我意识到mapv是更紧密的解决方案。简单的算术并不罕见,可以用来演示这样的东西。以下是一个Common Lisp的例子

(let ((channel (make-channel)))
  (submit-task channel '+ 3 4)
  (receive-result channel))

但是我确认您所预测的:在100,000次重复后,我得到

#{[1/2 1 3/2 2 5/2 3 7/2 4 9/2 5]
  [1 3/2 2 5/2 3 7/2 4 9/2 5 1/2]
  [1/2 1 3/2 2 5/2 3 7/2 4 9/2]
  [1/2 1 2 5/2 3 7/2 4 9/2 5 3/2]}
by
据我所知,Common Lisp中的通道与`clojure.core.async`中的通道并不相同。它们更像是与某个线程通信的一种方式。在Clojure中,如果您只想在单独的线程中运行一系列计算,那么最好仅使用`future`或`pmap`(尽管通常建议避免使用`pmap`而是使用可控制的东西)。在Clojure中,异步通道如果有需要在某个位置提供值,可能在这些值的上方进行一些计算,并在第三个位置接收结果,而这些位置可能根本不了解彼此,这将很有用。例如,生产者可能使用`(a/to-chan! (range 1 11))`,转换者可能使用`(a/map #(/ % 2) [channel])`,消费者可能使用`(a/go (let [all-values (a/<! (a/into [] transformed-channel))] ...))`。
by
当然,Clojure中的通道远不止这些。它们支持使用不同策略进行缓冲,允许实现反向压力,允许静态或动态地组合和分离通道,...
by
重新展示 by
谢谢。我现在开始清楚地看到它。我确实没有看到竞争条件。
...