我讀過很多關於Clojure在併發方面的優秀之處,但是我沒有閱讀過的教程實際上解釋瞭如何創建線程。你只是(.start(Thread。func)),還是有另一種我錯過的方式?如何在Clojure中啓動一個線程?
回答
Clojure fn
s是Runnable
因此,通常按照您發佈的方式使用它們,是的。
user=> (dotimes [i 10] (.start (Thread. (fn [] (println i)))))
0
1
2
4
5
3
6
7
8
9
nil
另一種選擇是使用agents,在這種情況下,你會send
或send-off
,它會使用一個線程池。
user=> (def a (agent 0))
#'user/a
user=> (dotimes [_ 10] (send a inc))
nil
;; ...later...
user=> @a
10
另一種選擇是pcalls
和pmap
。還有future
。他們都記錄在Clojure API。
是的,您在Clojure中啓動Java線程的方式就像您在那裏擁有的東西。
但是,真實的問題是:你爲什麼要這麼做? Clojure擁有多比線程更好的併發結構。
如果您看一下Clojure中的規範併發示例,Rich Hickey's ant colony simulation,您將看到它恰好使用0個線程。整個數據源中對java.lang.Thread
的唯一引用是對Thread.sleep
的三次調用,其唯一目的是減慢模擬速度,以便您實際上可以請參閱 UI中正在進行的操作。
所有的邏輯都在代理中完成:每個螞蟻一個代理,一個動畫代理和一個信息素蒸發代理。比賽場地是交易參考。不是一個線程或鎖定在視線內。
這是不正確的。 Clojure使用當然線程下的線程。但它提供了同步和協調這些線程的抽象,例如。期貨,pmap或代理商。然後出現問題,你想用java.util.concurrent機制來使用線程。 – kotarak 2009-11-20 06:39:09
我想給Jörg帶來這樣的疑問:當他說線程時,他的意思是線程API,但這應該清楚。 – 2009-11-20 06:47:59
Clojure在其內部運行時使用什麼來實現代理,期貨以及Rich Hickey的業務,而不是我的業務。事實上,Clojure的JVM版本恰好使用了線程池,這與語言語義完全無關。 Tomorrow Rich可能會改變主意並將它們實現爲Continuations,Clojure的.NET版本可能會將它們實現爲「任務」,ClojureScript(Clojure的JavaScript版本)可能將它們實現爲HTML5 Web Workers,並假設未來Erlang託管版本可能將它們實現爲Actor。作爲Clojure用戶,我永遠不會知道。 – 2009-11-20 07:08:20
編程Clojure直到頁167:「使用代理進行異步更新」才解決該問題。
在你開始線程之前,請注意Clojure將自己完成多任務,只要有一半機會。我已經寫出了對併發性無知的程序,並發現當條件合適時,它們佔用多個CPU。我知道這不是一個非常嚴格的定義:我還沒有深入探討這一點。
但是對於那些你確實需要明確的單獨活動的場合,Clojure的答案之一顯然是代理人。
(agent initial-state)
將創建一個。它不像是一個等待執行的代碼塊的Java線程。相反,這是一項等待開展工作的活動。你這樣做通過
(send agent update-fn & args)
的例子並
(def counter (agent 0))
counter
是你的名字,並辦理代理;代理的狀態是具有設置了數字0
,你可以把工作交給代理人:
(send counter inc)
會告訴它給定函數應用到它的狀態。
以後,您可以通過取消引用它拉出來的狀態的代理:
@counter
會給你,在0開始走出數的當前值。
功能await
會讓你這樣做對代理的活動join
,它應該是一個漫長的:
(await & agents)
將等待,直到他們全部完成;還有另一個版本需要超時。
使用未來通常是最簡單的adhoc訪問線程。完全取決於你想要做什麼:)
通常,當我想在Clojure中啓動一個線程時,我只需使用future。
除了使用簡單之外,這樣做的好處是可以避免執行任何繁瑣的Java互操作來訪問底層的Java線程機制。
實例:
(future (some-long-running-function))
這將在另一個線程異步執行該功能。
(def a (future (* 10 10)))
如果你想要得到的結果,只是取消引用的將來,e.g:
@a
=> 100
注意@a將阻塞,直到未來的線程已完成其工作。
(future f)
宏在Callable(通過fn *)封裝了表單f並將其立即提交給線程池。
,如果你需要一個java.lang.Thread中的對象的引用,例如,使用它作爲一個java.lang.Runtime中的關閉掛鉤,您可以創建這樣一個主題:
(proxy [Thread] [] (run [] (println "running")))
這不會啓動線程,只創建它。 創建和運行線程,將其提交給一個線程池,或致電。開始它:
(->
(proxy [Thread] [] (run [] (println "running")))
(.start))
Brians的回答也創建一個線程,但並不需要代理,所以這是非常優雅。另一方面,通過使用代理,我們可以避免創建一個Callable。
只需添加我的兩美分(7年後):Clojure功能實現IFn
interface,延伸Callable
以及Runnable
。因此,您可以簡單地將它們傳遞給像Thread
這樣的類。
如果你的項目可能已經使用core.async,我喜歡使用go
宏:
(go func)
這在執行func
超輕IOC (inversion of control) thread:
去 [...]會把身體變成一個狀態機。在達到任何阻塞操作時,狀態機將被「停放」並且實際的控制線程將被釋放。 [...]當阻塞操作完成後,該代碼將恢復[...]
如果func
會做I/O或需要長時間運行的任務,你應該使用thread
這也是core.async的部分(檢查this優秀博客文章):
(thread func)
無論如何,如果你想堅持到Java互操作的語法,請考慮使用->
(線程/箭頭)宏:
(-> (Thread. func) .start)
- 1. 如何在另一個線程內啓動線程
- 2. 在servlet中啓動一個新線程
- 3. 如何查看在Xcode中啓動了一個線程?
- 4. 如何在C#中啓動一個UI線程
- 5. 如何在BackgroundWorker中啓動線程?
- 6. 一個啓動線程一個沒有在Java中使用
- 7. 如何在django runserver啓動一個線程?
- 8. 如何中止另一個函數內部啓動的線程?
- 9. 如何在前一個線程完成後立即啓動新線程?
- 10. 如何「嘗試啓動」從其他多個線程一個線程,JAVA
- 11. Java:如何啓動同一對象的另一個線程?
- 12. 如何在Java代碼中啓動一組線程
- 13. 在Java中每個方法啓動一個線程
- 14. 如何在單線程中執行一些Clojure期貨?
- 15. C#啓動一個靜態線程
- 16. 同時啓動一個線程5次?
- 17. C#CF重新啓動一個線程
- 18. mq_notify只啓動一個線程
- 19. 如何在.NET中每次啓動最多X個線程?
- 20. 一個線程如何在另一個線程中被殺死
- 21. 如何從sockets.io啓動一個單獨的線程引發的線程
- 22. 使用moveToThread在PyQt5中啓動QThreads。一個線程無法正常啓動
- 23. 如何在android中重啓一個線程?
- 24. 如何啓動一個運行類函數的boost線程?
- 25. 如何從OpenCL代碼啓動另一個線程?
- 26. C++ boost ::線程,如何啓動線程內的線程
- 27. 多線程:啓動一個線程,而另一個進程不斷去
- 28. 如何在asp.net webforms中啓動一個新的長時間線程?
- 29. 如何在Java中啓動更多之前等待一個線程完成
- 30. BOOT_COMPLETE後在另一個線程中啓動服務
啊,是的,代理機制是我忘記的東西。謝謝! – andrewdotnich 2009-11-20 14:52:44
不要忘了pmap! – Dan 2009-11-26 13:29:23
「Clojure fns是可運行的,所以通常按照您發佈的方式使用它們,是的。」非常感謝您提供這些信息。 – sjas 2013-12-29 19:31:28