2013-10-10 102 views
2

我是Clojure的新手。我有多個線程試圖寫入輸出流,如果我沒有錯誤的套接字和他們的流不是線程安全的意思是位可以混合起來,如果我寫他們同時。 clojure的主要優點之一是內置的併發處理競爭條件。我如何將這個用於我的場景?Clojure多線程輸出流

我試着尋找原子,參考等。我最初認爲將輸出流聲明爲原子會起作用,但我不太確定,因爲它似乎避免了同時更改原子狀態(使用swap!),但我認爲您可以從多個線程取消引用原子,這意味着多個線程將deref保存我的輸出流的原子並同時寫入它。

任何建議將是最有幫助的。

在此先感謝

(defn send-my-data [output data-bytes] 
    (try 
    (.write output) 
    (.flush output) 
    (catch Exception excp 
     (println (format "issue %s" (.printStackTrace excp)))) 

現在我所有的線程調用這個函數任何時候他們想要的數據寫入到輸出流

回答

0

我最終實現了代理方法,因爲我認爲它更具慣用性和代理的其他好處。

(let [wtr (agent (.getOutputStream mysocket) "agent.log")] 
    (defn log [msg] 
     (letfn [(write [out msg] 
      (.write out msg) 
      (.flush out) 
       out)] 
     (send-off wtr write msg))) 
    (defn close [] 
     (send wtr #(.close %)))) 

改編自here

記住返回輸出流作爲代理人拿上返回的值。一個常見的錯誤。

謝謝 亞瑟Ulfeldt

0

,如果你需要確保沒有其他線程使用您可以使用locking一個對象(並且希望在代碼中的那一刻等待,並且在該對象未鎖定之前不在該特定線程中執行任何操作,以便可以鎖定該對象)。

user> (dotimes [i 10] (future (println \h \e \l \l \o))) 
hhh h e 
nil 
eh le l lo 
h e lh he e ll h el ll lo 
e e l l oh 
l l oo 
l ol 

l lo o 

e 

o 
l l o 

user> (dotimes [i 10] (future (locking *out* (println \h \e \l \l \o)))) 
h 
nil 
e l l o 
h e l l o 
h e l l o 
h e l l o 
h e l l o 
h e l l o 
h e l l o 
h e l l o 
h e l l o 
h e l l o 

user> 
5

代理通常被認爲是這類任務的正確工具。他們需要一系列的任務來運行他們的內部狀態,並按照他們收到的順序運行它們。他們也與Clojure的其他STM搭配得很好。例如發送到事務中的代理表單的消息只會在事務提交時發送一次

user> (let [output-agent (agent "")] 
     (dotimes [x 10] 
      (send output-agent (fn [_] (println "hello" x))))) 
nil 
hello 0 
hello 1 
hello 2 
hello 3 
hello 4 
hello 5 
hello 6 
hello 7 
hello 8 
hello 9 

在這個例子中,要採取的動作是一個匿名函數,忽略它的輸入並只是打印一些東西。

+0

根據我提供我怎麼能實現你的方法示例代碼。我想我很難理解代理數據類型的概念,因爲我試圖將它與其他基本數據類型進行比較。我不完全確定實際的輸出代理在上面的例子中做了什麼。對不起,如果它有點如果一個新手問題。我真的很想理解clojure併發的力量。 – sqwale

+0

在此示例中,輸出代理程序的內容完全未使用,輸出代理程序正在用作任務隊列,該事務隊列與事務很好地協同工作,並將收集任何異常以供以後檢查。每次發送調用都會將一個函數運行到代理輸入隊列中,然後代理線程池將按照特定代理線程池中線程接收到的順序運行輸入隊列中的函數。如果您發送長時間運行的作業並且或者需要限制並行任務,那麼值得了解send-off和send-via函數。 –