Multithreading 与Clojure的线程同步
我做了一个练习:Multithreading 与Clojure的线程同步,multithreading,clojure,clojure-java-interop,Multithreading,Clojure,Clojure Java Interop,我做了一个练习: 按从1到100的顺序打印所有正整数 使用块、信号量或其他类似机制(但避免睡眠),协调两个线程,使两个线程的组合输出以数字顺序显示 Sample Output In thread one: The number is ‘1’ In thread two: The number is ‘2’ In thread one: The number is ‘3’ In thread two: The number is ‘4’ 这个练习是针对Ru
- 按从1到100的顺序打印所有正整数
- 使用块、信号量或其他类似机制(但避免睡眠),协调两个线程,使两个线程的组合输出以数字顺序显示
Sample Output In thread one: The number is ‘1’ In thread two: The number is ‘2’ In thread one: The number is ‘3’ In thread two: The number is ‘4’
(def thread_1 (future (swap! my-atom inc) ))
(def thread_2 (future (swap! my-atom inc) ))
但是@thread_1总是返回相同的值。有没有办法协调Clojure中的两个线程
我在Java中使用ReentrantLock和Condition发现了这一点,现在我正在尝试将其转换为Clojure。首先,您看到奇怪结果的原因是您取消了对未来的引用,而不是保留数字的原子。未来将返回
交换的结果代码>取消引用时
其次,您可以使用锁定
(基本上是Java的同步
)一次只允许增加一个线程并打印:
(def n-atom (atom 0))
(defn action []
; Arbitrarily chose the atom to lock on.
; It would probably be better to create a private object that can't be otherwise used.
(locking n-atom
(println
(swap! n-atom inc))))
(defn go []
; Have each thread do action twice for a total of four times
(future (doall (repeatedly 2 action)))
(future (doall (repeatedly 2 action))))
(go)
1
2
3
4
不过我要注意的是,这里确实不应该使用future
future
用于异步计算结果。它会吞噬错误,直到它被解除引用,因此如果您从未@
,您将永远不会看到未来中出现的异常。最好使用线程池,或者在宏的帮助下,自己启动两个线程以便于使用:
(defmacro thread
"Starts the body in a new thread."
[& body]
`(doto (Thread. ^Runnable (fn [] ~@body))
(.start)))
(defn go []
(thread (doall (repeatedly 2 action)))
(thread (doall (repeatedly 2 action))))
下面是一种使用以下命令协调在同一状态下运行的多个线程的方法:
如果线程的顺序确实重要,并且如果您对非经典线程通信感到好奇,那么可以使用clojure.core.async
并使用“通道”
这里的一个问题是go例程是在线程池中执行的,因此它们不是专用线程,如果您想使用真正的线程,您应该这样做:
(require '[clojure.core.async :as a])
(let [chan-one (a/chan 1)
chan-two (a/chan 1)]
(a/>!! chan-one 1)
(doseq [[thread in out] [["one" chan-one chan-two]
["two" chan-two chan-one]]]
(a/thread
(loop []
(when-let [n (a/<!! in)]
(if (> n 10)
(do (a/close! in)
(a/close! out))
(do (prn (format "In thread %s: The number is `%s`" thread n))
(a/>!! out (inc n))
(recur))))))))
(需要“[clojure.core.async:作为])
(让[chan one(a/chan 1)
第二条(a/chan 1)]
(a/>!!chan one 1)
(doseq[[thread in out][[1”chan一chan二]
[“两”灿二灿一]]
(a/线程
(循环[]
(出租时[n(a/n 10)
(do(a/close!in)
(a/关闭!关闭)
(do(prn(线程%s中的格式:编号为“%s”线程n))
(a/>!!out(inc n))
(重复(()(())(())))
顺序重要吗?我的意思是线程应该一个接一个地工作,就像你的例子一样。@fl00r,是的,顺序必须是顺序的。这里的信息没有错,但是…使用验证器进行普通终止?让未来在普通终止时崩溃?好吧,这个例子可以改进。@glts公平点!请参阅更新的答案如果你能想到其他的改进,请告诉我。
(def my-agent (agent (range 1 101)))
(while (seq @my-agent)
(send
my-agent
(fn [[n & ns]]
(when n
(println "In thread" (.getName (Thread/currentThread))
"the number is:" n)
ns))))
(require '[clojure.core.async :as a])
(let [chan-one (a/chan 1)
chan-two (a/chan 1)]
(a/>!! chan-one 1)
(doseq [[thread in out] [["one" chan-one chan-two]
["two" chan-two chan-one]]]
(a/go-loop []
(when-let [n (a/<! in)]
(if (> n 10)
(do (a/close! in)
(a/close! out))
(do (prn (format "In thread %s: The number is `%s`" thread n))
(a/>! out (inc n))
(recur)))))))
"In thread one: The number is `1`"
"In thread two: The number is `2`"
"In thread one: The number is `3`"
"In thread two: The number is `4`"
"In thread one: The number is `5`"
"In thread two: The number is `6`"
"In thread one: The number is `7`"
"In thread two: The number is `8`"
"In thread one: The number is `9`"
"In thread two: The number is `10`"
(require '[clojure.core.async :as a])
(let [chan-one (a/chan 1)
chan-two (a/chan 1)]
(a/>!! chan-one 1)
(doseq [[thread in out] [["one" chan-one chan-two]
["two" chan-two chan-one]]]
(a/thread
(loop []
(when-let [n (a/<!! in)]
(if (> n 10)
(do (a/close! in)
(a/close! out))
(do (prn (format "In thread %s: The number is `%s`" thread n))
(a/>!! out (inc n))
(recur))))))))