【发布时间】:2016-10-05 04:52:17
【问题描述】:
假设我在 Clojure 中有一个向量:
(def myvec (atom (vector 1)))
我有这个函数可以为向量添加新值:
(defn inc-myvec! []
(swap! myvec conj (inc (last @myvec))))
假设在某个触发器上不时调用此函数。让我们触发几次。
(dotimes [i 5] (inc-myvec!))
@myvec
;=> [1 2 3 4 5 6]
现在,如果我想从该向量中的每个元素中减去 1,我会这样做:
(def myvec2 (atom (mapv dec @myvec)))
@myvec2
;=> [0 1 2 3 4 5]
这当然不是很好,因为我必须在每次更改 myvec 时都这样做。这也很浪费,因为它在每次更改时都会处理整个向量。我们可以做得更好。让我们实现观察者模式并只计算最后一个附加的值:
(defn watcher [_ _ _ new-myvec]
(swap! myvec2 conj (dec (last new-myvec))))
(add-watch myvec :watcher watcher)
这还不错。但理想情况下,我希望观察者在另一个线程中操作初学者。是否有更好、更惯用的方法来处理这种转换,您基本上需要在传入数据流到达时对其做出反应并将其转换为其他东西?
【问题讨论】:
-
我不确定您要在这里改进什么。你能制定一般用例吗?有用于操作流的库,但您的示例几乎不是关于流恕我直言(为什么是向量,为什么是原子?)。如果我要优化您的示例,我会使用自定义的“范围”数据结构(与整数的 2 元组一样轻量级)。
-
@ValentinWaeselynck 一般用例是根据另一个向量计算一个向量。向量不是示例的重要部分,可以是地图或列表。我正在使用加法和减法,但在现实生活中,这将是相对密集的计算。因此,我想在另一个线程中进行第二次操作(这就是我使用原子的原因),而对于手表来说这是不可能的(尽管我可以在手表内部分叉未来)。我不确定这是什么困扰着我;我想我可以接受人们告诉我这没关系,但不知何故,我希望听到“不傻,这不是它的完成方式”。 :)
-
一般用例真的是关于基于整个其他集合计算整个集合吗? (非常不像流)因为在您的最后一个改进中,您似乎可以只更新最后一个值。很抱歉坚持,但通常答案在于更好地提出问题:)
-
@ValentinWaeselynck - 当然!我正在处理的输入集合是无穷无尽的,读取速度相对较快,最多每秒几次。输出收集基于输入值,但在某个时期(每分钟不少于一个值)。想法是在输入进入时计算输出。我计算整个事情的例子只是一个起点,最后一个例子是我正在寻找的更多。我最多使用来自集合尾部的几个值或输入中的最后一个值来计算输出中的最新值。
-
这绝对是流 - 检查核心异步并摆脱那些原子 :)