莊周夢蝶

          生活、程序、未來
             :: 首頁 ::  ::  :: 聚合  :: 管理

          Clojure的并發(六)Agent可以改進的地方

          Posted on 2010-07-30 21:35 dennis 閱讀(3252) 評論(0)  編輯  收藏 所屬分類: Clojure
          Clojure 的并發(一) Ref和STM
          Clojure 的并發(二)Write Skew分析
          Clojure 的并發(三)Atom、緩存和性能
          Clojure 的并發(四)Agent深入分析和Actor
          Clojure 的并發(五)binding和let
          Clojure的并發(六)Agent可以改進的地方
          Clojure的并發(七)pmap、pvalues和pcalls
          Clojure的并發(八)future、promise和線程

              前面幾節基本介紹Clojure對并發的支持,估計這個系列還能寫個兩三節,介紹下一些常見的concurrent function的使用。談了很多優點,現在想談談clojure的一些缺憾,例如Agent系統。

              Agent在前面已經介紹過了,用于異步更新,基本的原理是將更新操作封裝為action,提交給線程池處理。內部有兩個線程池,固定大小(cpus+2)的線程池用于處理send發送的action,而send-off發送的action則是由一個Cached ThreadPool處理的。因此,如果你的更新操作很耗時或者會阻塞(如IO操作),那么通常是建議使用send-off,而send適合一些計算密集型的更新操作。兩個線程池的聲明如下(Agent.java):
          1 final public static ExecutorService pooledExecutor =
          2         Executors.newFixedThreadPool(2 + Runtime.getRuntime().availableProcessors());
          3 
          4 final public static ExecutorService soloExecutor = Executors.newCachedThreadPool();

              說說我認為Agent可以改進的地方。
              首先是從實踐角度出發,通常我們要求new一個線程池的時候,要設置線程池內線程的name,以方便查看和調試。因此Clojure這里簡單的new線程池是一個可以改進的地方,應當自定義一個ThreadFactory,給clojure的Agent線程提供明確的名稱。

              其次,由于這兩個線程池是全局的,因此clojure提供了shutdown-agents的方法用于關閉線程池。但是由于這些線程池內的線程并非daemon,因此如果你沒有明確地調用shutdown-agents,jvm也可以正常退出。我們都知道,如果還有dadmon線程沒有終止,JVM是無法退出的。如果JVM只剩下daemon線程,那么jvm就會自動退出。從實踐角度,應當明確地要求用戶調用shutdown-agents來關閉Agent系統,妥善終止線程,并且Agent的線程池應當延遲初始化,只在必要的時候創建,而非現在的靜態變量。所以,在實現ThreadFactory的時候,應當設置生成的線程為daemon。

              第三,同樣由于線程池是全局的,關閉了卻沒有辦法重新啟動,這不能不說是一個缺憾。Clojure沒有提供重新啟動的方法。

              第四,線程池簡單地分為兩類,從理論上足以滿足大部分應用的要求。但是在real world的應用上,我們通常不敢用CachedThreadPool,這是為了防止內存不受控,導致線程創建過多直接OOM。通常我們會使用固定大小的線程池,但是clojure固定大小的線程池只有一個,并且大小寫死為cpus+2,這就沒有了控制的余地。我還是希望clojure能提供允許自定義Agent線程池的方法,可以在創建的時候傳入線程池,如:
          (agent :executor (java.util.concurrent.Executors/newFixedThreadPool 2))

          或者提供新的API,如set-executor!來設置agent使用的線程池,如果沒有自定義線程池再使用全局的。當然也需要提供一個關閉agent自定義線程池的API:
          (shutdown-agent agent)

              需要自定義線程池是另一個原因是為了最大化地發揮線程池的效率,我們知道,線程池只有在執行“同構”任務的時候才能發揮最大的效率,如果有的 action快,有的action慢,那么該快的快不起來,慢的卻擠占了快的action的執行時間。通過給Agent設定自己的線程池某些程度上可以解決這個問題。


             Agent的整個模型是很優雅的,但是確實還有這些地方不是特別讓人滿意,希望以后會得到改進。

          主站蜘蛛池模板: 邢台市| 时尚| 兴安县| 邻水| 北安市| 呼伦贝尔市| 时尚| 龙口市| 连山| 郁南县| 博野县| 嘉禾县| 边坝县| 普兰县| 奇台县| 文水县| 博野县| 广南县| 西充县| 博兴县| 津市市| 东阳市| 休宁县| 辽宁省| 莫力| 揭东县| 朝阳县| 平山县| 英吉沙县| 广宁县| 翁牛特旗| 灵武市| 项城市| 五家渠市| 崇阳县| 仲巴县| 孟连| 屯留县| 烟台市| 易门县| 车致|