Clojure生产者消费者

Clojure生产者消费者,clojure,Clojure,我正在学习clojure,并通过一个生产者-消费者示例来测试它的并发性和有效性 做到了这一点,我感到非常尴尬,因为我不得不使用ref和deref,还要观看和取消比赛 我试图检查其他代码片段;但是除了使用Java条件await()和signal()方法以及Java锁之外,还有更好的方法来重新分解它吗。我不想在Java中使用任何东西 这是代码;我想我在这里会犯很多错误 ;a simple producer class (ns my.clojure.producer (:use my.clo

我正在学习clojure,并通过一个生产者-消费者示例来测试它的并发性和有效性

做到了这一点,我感到非常尴尬,因为我不得不使用ref和deref,还要观看和取消比赛

我试图检查其他代码片段;但是除了使用Java条件await()和signal()方法以及Java锁之外,还有更好的方法来重新分解它吗。我不想在Java中使用任何东西

这是代码;我想我在这里会犯很多错误

;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解决方案的吸引力,但它会很好地工作。

我遇到了几个需要具备以下能力的用例:

  • 严格控制生产者和消费者端的工作线程数量
  • 控制“工作队列”的最大大小以限制内存消耗
  • 检测所有工作何时完成,以便我可以关闭工人
我发现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))

欢迎反馈/建议/贡献!

我遇到了几个用例,我需要能够:

  • 严格控制生产者和消费者端的工作线程数量
  • 控制“工作队列”的最大大小以限制内存消耗
  • 检测所有工作何时完成,以便我可以关闭工人
我发现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))

欢迎反馈/建议/贡献!

谢谢,我相信这是最好的方式,但我现在不想使用任何库,因为我正在学习我想使用全局任务列表,并通过取消引用将其提供给其他功能(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))