Clojure 具有core.async的节流功能
应限制函数可能执行的次数。因此,在调用函数后,任何重复调用都应该在一段时间内被忽略。如果同时存在where调用,则应在时间段之后执行最后一个调用 下面是我使用core.async的方法。这里的问题是,额外的调用在通道c中汇总。我需要一个通道,里面只有一个位置,它将被put覆盖!每次都是Clojure 具有core.async的节流功能,clojure,clojurescript,core.async,Clojure,Clojurescript,Core.async,应限制函数可能执行的次数。因此,在调用函数后,任何重复调用都应该在一段时间内被忽略。如果同时存在where调用,则应在时间段之后执行最后一个调用 下面是我使用core.async的方法。这里的问题是,额外的调用在通道c中汇总。我需要一个通道,里面只有一个位置,它将被put覆盖!每次都是 (defn throttle [f time] (let [c (chan 1)] (go-loop [] (apply f (<! c)) (<! (timeou
(defn throttle [f time]
(let [c (chan 1)]
(go-loop []
(apply f (<! c))
(<! (timeout time))
(recur))
(fn [& args]
(put! c (if args args [])))))
有人知道如何解决这个问题吗
解决方案
(除油门[f时间]
(让[c(chan(滑动缓冲器1))]
(转到循环[]
(应用f(您可以使用函数
我会把它复制到这里:
(defn debounce [in ms]
(let [out (chan)]
(go-loop [last-val nil]
(let [val (if (nil? last-val) (<! in) last-val)
timer (timeout ms)
[new-val ch] (alts! [in timer])]
(condp = ch
timer (do (>! out val) (recur nil))
in (recur new-val))))
out))
这是debounce
的版本,将根据问题的要求输出,即立即为0,然后等待4秒钟,然后是9:
(defn debounce [in ms]
(let [out (chan)]
(go-loop [last-val nil
first-time true]
(let [val (if (nil? last-val) (<! in) last-val)
timer (timeout (if first-time 0 ms))
[new-val ch] (alts! [in timer])]
(condp = ch
timer (do (>! out val) (recur nil false))
in (recur new-val false))))
out))
(反弹力[以毫秒为单位]
(放[出(陈)]
(go loop[最后一个值为零
第一次正确]
(让[val(如果(无?最后一个val)(!out val)(重复无错误))
在(重复新val false)中)
出局
我使用的是log
,而不是像你那样使用print
。你不能依赖println/print
函数的core.async
。请参阅以获取解释。要解决频道问题,你可以使用带有滑动缓冲区的chan:
user> (require '[clojure.core.async :as async])
nil
user> (def c (async/chan (async/sliding-buffer 1)))
#'user/c
user> (async/>!! c 1)
true
user> (async/>!! c 2)
true
user> (async/>!! c 3)
true
user> (async/<!! c)
3
user>(需要“[clojure.core.async:as async]”
无
用户>(定义c(异步/通道(异步/滑动缓冲区1)))
#'用户/c
用户>(异步/>!!c 1)
真的
用户>(异步/>!!c 2)
真的
用户>(异步/>!!c 3)
真的
用户>(异步)/
这样,在下一个间隔中,只计算最后输入通道的值。这是从David处获取的:
您可能还想在通道中添加一个重复数据消除传感器。我需要传递一个函数来捕获args,因为我将它用于输入事件,它传递的是一个可变对象。看起来像是一个更复杂的结构,我无法立即掌握。除了alre,我的方法在某种程度上讲不通吗ady提到了不当行为?我的意思是,这不能很容易地以某种方式解决吗?另请参见:IMO这不是节流,如果生产者和消费者都很快,就不会丢弃消息。答案不完整,但也没有错。一些消费者加上超时和使用滑动缓冲区
会产生错误完整答案。谢谢!第二个示例性代码示例展示了一个实际应用程序,这将使您的答案成为首选:)还希望看到重复数据消除的实施
(defn my-sender [to-chan values]
(go-loop [[x & xs] values]
(>! to-chan x)
(when (seq xs) (recur xs))))
(defn my-receiver [from-chan f]
(go-loop []
(let [res (<! from-chan)]
(f res)
(recur))))
(defn setup-and-go []
(let [in (chan)
ch (debounce in 4000)
sender (my-sender in (range 10))
receiver (my-receiver ch #(log %))]))
(defn debounce [in ms]
(let [out (chan)]
(go-loop [last-val nil
first-time true]
(let [val (if (nil? last-val) (<! in) last-val)
timer (timeout (if first-time 0 ms))
[new-val ch] (alts! [in timer])]
(condp = ch
timer (do (>! out val) (recur nil false))
in (recur new-val false))))
out))
user> (require '[clojure.core.async :as async])
nil
user> (def c (async/chan (async/sliding-buffer 1)))
#'user/c
user> (async/>!! c 1)
true
user> (async/>!! c 2)
true
user> (async/>!! c 3)
true
user> (async/<!! c)
3
(defn throttle*
([in msecs]
(throttle* in msecs (chan)))
([in msecs out]
(throttle* in msecs out (chan)))
([in msecs out control]
(go
(loop [state ::init last nil cs [in control]]
(let [[_ _ sync] cs]
(let [[v sc] (alts! cs)]
(condp = sc
in (condp = state
::init (do (>! out v)
(>! out [::throttle v])
(recur ::throttling last
(conj cs (timeout msecs))))
::throttling (do (>! out v)
(recur state v cs)))
sync (if last
(do (>! out [::throttle last])
(recur state nil
(conj (pop cs) (timeout msecs))))
(recur ::init last (pop cs)))
control (recur ::init nil
(if (= (count cs) 3)
(pop cs)
cs)))))))
out))
(defn throttle-msg? [x]
(and (vector? x)
(= (first x) ::throttle)))
(defn throttle
([in msecs] (throttle in msecs (chan)))
([in msecs out]
(->> (throttle* in msecs out)
(filter #(and (vector? %) (= (first %) ::throttle)))
(map second))))