2017-02-24 59 views
4

我想要計算事件的發生率,例如按鍵事件,並顯示它。我也想在事件發生後纔開始計算費率。另一個要求是,在一定數量的按鍵事件之後,費率計算應該停止。我目前的做法是計算Clojure頻道中的事件發生率

(defn keypress-chan 
    "Returns a channel that receives keys" 
    [] 
    (let [out (chan) handler (fn [e] (put! out (.-key e)))] 
    (js/document.addEventListener "keypress" handler false) 
    out)) 

(defn tick 
    "Pushes to `out` 1000 ms later" 
    [out] 
    (go 
    (<! (timeout 1000)) 
    (>! out 1))) 

(defn get-rate 
    "Calculates keypress per minute rate" 
    [ticks pressed] 
    (quot (* pressed 60) ticks)) 

(defn complete? 
    [count] 
    (>= count 100)) 

(defn main-loop [] 
    (let [key-chan (keypress-chan) ticker-chan (chan)] 
    (go-loop [pressed 0 ticks 0] 
     (let [[value ch] (alts! [key-chan ticker-chan])] 
     (if (= ch key-chan) 
      (do 
      ;; Start timer to calculate keypress rate 
      (if (zero? pressed) 
       (tick ticker-chan)) 

      ;; Do something with `value`, i. e. the key being pressed 

      (when-not (complete?) 
       (recur (inc pressed) ticks))) 

      (let [speed (get-rate ticks pressed)] 
      (swap! app-state assoc :rate rate) 
      (tick ticker-chan) 
      (recur pressed (inc ticks)))))))) 

所以,這個工作,但在main-loop代碼似乎醜陋的我。我一直在想有一個「觸發器」,只有當第一個值出現在key-chan並啓動計時器時纔會觸發。然後另一個觸發器在必要時停止定時器。但我是Clojure的新手,不太清楚如何使用async,所以我無法創建比上述代碼更好的東西。

這個循環如何改進? 我可以將定時器移動到某個功能並通過key-chan中的第一個值啓動定時器嗎? 如何在稍後停止計時器?

+0

我會保存時間戳在排序列表中的每個按鍵,然後計算在過去的60秒的移動平均率。首先,我不會擔心丟棄舊的價值觀;只需在當前時間的60秒內提取所有值,然後對其進行計數,這就是您的平均速率/分鐘。 –

+0

@AlanThompson,感謝您的想法!將嘗試它。 – coquin

回答

0

我想出了以下解決方案。

(ns ratecalc.core 
    (:require [cljs.core.async :refer [chan <! go-loop]]) 
    (:import [goog.date DateTime])) 

(defn calc-rate [input-chan do-fun max-count] 
    (go-loop [count 0 
      start-time nil] 
    (<! input-chan) 
    (let [inc-count (inc count) 
      now (.getTime (DateTime.)) 
      start-time* (if-not start-time now start-time) 
      rate-per-ms (/ inc-count (- now start-time*))] 
     (do-fun rate-per-ms) 
     (if (= count max-count) 
     rate-per-ms 
     (recur inc-count start-time*))))) 

calc-rate函數計算每毫秒的通道上的消息的數量。你可以傳遞一個函數來做一些副作用,比如打印當前的平均值。最後一個參數將其計算限制爲最大數量的消息。下面是如何使用它的一個例子:

(calc-rate (keypress-chan) println 10)