Clojure生产者消费者
我正在学习clojure,并通过一个生产者-消费者示例来测试它的并发性和有效性 做到了这一点,我感到非常尴尬,因为我不得不使用ref和deref,还要观看和取消比赛 我试图检查其他代码片段;但是除了使用Java条件await()和signal()方法以及Java锁之外,还有更好的方法来重新分解它吗。我不想在Java中使用任何东西 这是代码;我想我在这里会犯很多错误Clojure生产者消费者,clojure,Clojure,我正在学习clojure,并通过一个生产者-消费者示例来测试它的并发性和有效性 做到了这一点,我感到非常尴尬,因为我不得不使用ref和deref,还要观看和取消比赛 我试图检查其他代码片段;但是除了使用Java条件await()和signal()方法以及Java锁之外,还有更好的方法来重新分解它吗。我不想在Java中使用任何东西 这是代码;我想我在这里会犯很多错误 ;a simple producer class (ns my.clojure.producer (:use my.clo
;a simple producer class
(ns my.clojure.producer
(:use my.clojure.consumer)
(:gen-class)
)
(def tasklist( ref (list) )) ;this is declared as a global variable; to make this
;mutable we need to use the fn ref
(defn gettasklist[]
(deref tasklist) ;we need to use deref fn to return the task list
)
(def testagent (agent 0)); create an agent
(defn emptytasklist[akey aref old-val new-val]
(doseq [item (gettasklist)]
(println(str "item is") item)
(send testagent consume item)
(send testagent increment item)
)
(. java.lang.Thread sleep 1000)
(dosync ; adding a transaction for this is needed to reset
(remove-watch tasklist "key123"); removing the watch on the tasklist so that it does not
; go to a recursive call
(ref-set tasklist (list ) ) ; we need to make it as a ref to reassign
(println (str "The number of tasks now remaining is=") (count (gettasklist)))
)
(add-watch tasklist "key123" emptytasklist)
)
(add-watch tasklist "key123" emptytasklist)
(defn addtask [task]
(dosync ; adding a transaction for this is needed to refset
;(println (str "The number of tasks before") (count (gettasklist)))
(println (str "Adding a task") task)
(ref-set tasklist (conj (gettasklist) task )) ; we need to make it as a ref to reassign
;(println (str "The number of tasks after") (count (gettasklist)))
)
)
这是消费者代码
(ns my.clojure.consumer
)
(defn consume[c item]
(println "In the consume method:Item is " c item )
item
)
(defn increment [c n]
(println "parmeters are" c n)
(+ c n)
)
下面是测试代码(我使用maven运行clojure代码,使用NetBeans进行编辑,因为我更熟悉Java文件夹结构和pom中的这一点-
如果有人能轻松地重构它,这样我就可以阅读和理解代码,那就太棒了;否则我想我还需要学习更多
编辑-1
我猜在clojure中,使用全局任务列表并通过取消引用(deref)使其可供其他函数使用并再次通过ref使其可变不是一种方式 因此,将addTask方法更改为直接将传入任务发送给代理
(defn addtask [task]
(dosync ; adding a transaction for this is needed to refset
(println (str "Adding a task") task)
;(ref-set tasklist (conj (gettasklist) task )) ; we need to make it as a ref to reassign
(def testagent (agent 0)); create an agent
(send testagent consume task)
(send testagent increment task)
)
但是当我测试它的时候
(deftest test-addandcheck
(loop [task 0]
(when ( < task 100)
(addtask task)
(recur (inc task))))
(is(= 0 (count (gettasklist))))
(println (str "The number of tasks are") (count (gettasklist)))
)
我曾在年制作过类似的clojure节目,采用制作人/消费者模式 我不认为你真的需要使用裁判。 您有一个任务列表,它是要同步更改的可变状态。更改相对较快,不依赖于任何其他外部状态,只依赖于传入使用者的变量 就原子而言,有交换!功能可以帮助您按照我理解的方式进行所需的更改 你可以看看我的代码片段,我想它至少可以告诉你原子和代理的正确用法。我经常使用它,所以它应该是正确的 希望有帮助 问候,,
Jan我在年制作了类似的clojure节目,采用制作人/消费者模式 我不认为你真的需要使用裁判。 您有一个任务列表,它是要同步更改的可变状态。更改相对较快,不依赖于任何其他外部状态,只依赖于传入使用者的变量 就原子而言,有交换!功能可以帮助您按照我理解的方式进行所需的更改 你可以看看我的代码片段,我想它至少可以告诉你原子和代理的正确用法。我经常使用它,所以它应该是正确的 希望有帮助 问候,,
Jan我认为在clojure为制片人和消费者建模是最容易(也是最有效)的。我认为在clojure为制片人和消费者建模是最容易(也是最有效)的使用。我在看Twitter storm的Clojure示例。他刚刚使用了。它易于使用,并发,性能良好。当然,它没有固定Clojure解决方案的吸引力,但它会很好地工作。我在看Twitter storm的Clojure示例。他刚刚使用了。它易于使用,并发,性能良好。s当然,它缺乏不可改变的Clojure解决方案的吸引力,但它会很好地工作。我遇到了几个需要具备以下能力的用例:
- 严格控制生产者和消费者端的工作线程数量
- 控制“工作队列”的最大大小以限制内存消耗
- 检测所有工作何时完成,以便我可以关闭工人
lamina
看起来很棒,但我没有看到一种方法可以解决我的特定用例,而不需要与基于BlockingQueue
的实现类似的额外管道
因此,我最终拼凑了一个简单的clojure库来解决我的问题。它基本上只是一个围绕BlockingQueue
的包装器,试图隐藏一些Java构造并提供更高级别的生产者-消费者API。我还不完全满意该API;它可能会进一步发展……但它是操作:
用法示例:
(def myproducer (producer producer-work-fn num-workers max-work))
(def myconsumer (consumer myproducer consumer-work-fn num-workers max-results))
(doseq [result (work-queue->seq (:result-queue myconsumer))]
(println result))
欢迎反馈/建议/贡献!我遇到了几个用例,我需要能够:
- 严格控制生产者和消费者端的工作线程数量
- 控制“工作队列”的最大大小以限制内存消耗
- 检测所有工作何时完成,以便我可以关闭工人
lamina
看起来很棒,但我没有看到一种方法可以解决我的特定用例,而不需要与基于BlockingQueue
的实现类似的额外管道
因此,我最终拼凑了一个简单的clojure库来解决我的问题。它基本上只是一个围绕BlockingQueue
的包装器,试图隐藏一些Java构造并提供更高级别的生产者-消费者API。我还不完全满意该API;它可能会进一步发展……但它是操作:
用法示例:
(def myproducer (producer producer-work-fn num-workers max-work))
(def myconsumer (consumer myproducer consumer-work-fn num-workers max-results))
(doseq [result (work-queue->seq (:result-queue myconsumer))]
(println result))
欢迎反馈/建议/贡献!谢谢,我相信这是最好的方式,但我现在不想使用任何库,因为我正在学习我想使用全局任务列表,并通过取消引用将其提供给其他功能(deref)同样,在clojure中,通过ref使其可变不是最好的方法;谢谢,我确信这是最好的方法,但我现在不想使用任何库,因为我正在学习,我想使用全局任务列表和mak
(def myproducer (producer producer-work-fn num-workers max-work))
(def myconsumer (consumer myproducer consumer-work-fn num-workers max-results))
(doseq [result (work-queue->seq (:result-queue myconsumer))]
(println result))