3

我是 Clojure 的新手。我有多个线程试图写入输出流,如果我没记错套接字并且它们的流不是线程安全的,这意味着如果我同时写入它们,位可能会混淆。clojure 的主要好处之一是对竞争条件的内置并发处理。我如何在我的场景中使用它?

我尝试研究原子、参考文献等。我最初认为将输出流声明为原子会起作用,但我不太确定,因为它似乎避免同时更改原子状态(使用交换!)但是我认为你可以从多个线程中取消引用原子,这意味着多个线程将deref 持有我的输出流的原子并同时写入它。

任何建议都将是最有帮助的。

提前致谢

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

现在我所有的线程在他们想要将数据写入输出流的任何时候都会调用这个函数

4

3 回答 3

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

在这个例子中,要采取的行动是一个匿名函数,它忽略它的输入,只是打印一些东西。

于 2013-10-10T21:53:11.953 回答
1

如果您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> 
于 2013-10-10T20:44:23.053 回答
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 %))))

改编自这里

请记住在代理接受返回值时返回输出流。一个常见的错误。

谢谢亚瑟·乌尔费尔特

于 2013-12-01T18:44:48.877 回答