【问题标题】:How can I create a constantly running background process in Clojure?如何在 Clojure 中创建一个持续运行的后台进程?
【发布时间】:2011-06-01 10:17:17
【问题描述】:

如何在 Clojure 中创建一个持续运行的后台进程?使用“未来”的循环永远不会以正确的方式结束吗?

【问题讨论】:

    标签: concurrency clojure


    【解决方案1】:

    你可以用一个永远运行的函数来启动一个线程。

    (defn forever []
      ;; do stuff in a loop forever
    )
    
    (.start (Thread. forever))
    

    如果您不希望后台线程阻止进程退出,请确保将其设为守护线程:

    (doto 
       (Thread. forever)
       (.setDaemon true)
       (.start))
    

    如果您想要更多技巧,可以使用 java.util.concurrent.Executors 工厂来创建 ExecutorService。这使得创建线程池、使用自定义线程工厂、自定义传入队列等变得容易。

    claypoole lib 将一些工作执行的东西包装成一个对 clojure 更友好的 api,如果那是你想要的。

    【讨论】:

      【解决方案2】:

      我的简单高阶无限循环函数(使用期货):

      (def counter (atom 1))
      
      (defn infinite-loop [function]   
        (function)
        (future (infinite-loop function))
        nil) 
      
      ;; note the nil above is necessary to avoid overflowing the stack with futures...
      
      (infinite-loop 
        #(do 
           (Thread/sleep 1000) 
           (swap! counter inc)))
      
      ;; wait half a minute....
      
      @counter
      => 31
      

      我强烈建议使用原子或 Clojures 其他引用类型之一来存储结果(如上例中的计数器)。

      通过一些调整,您还可以使用这种方法以线程安全的方式启动/停止/暂停进程(例如,测试一个标志以查看是否应该在循环的每次迭代中执行(函数))。

      【讨论】:

      • 附注也很高兴知道这种方法的开销非常小 - 如果您删除 Thread/sleep,则每秒可以获得超过一百万个计数器增量
      • 另一个不消耗栈的简单实现(defn infinite [f seconds] (future (loop [] (f) (Thread/sleep (* seconds 1000)) (recur))))
      • @James - 我的实现也不消耗堆栈。对 infinite-loop 的递归调用在未来内部这一事实意味着它不会在原始函数的堆栈框架内重复。
      【解决方案3】:

      也许,或者也许是 Lein-daemon? https://github.com/arohner/lein-daemon

      【讨论】:

      • 它允许你暂停执行吗?
      猜你喜欢
      • 1970-01-01
      • 2019-08-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-01-30
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多