agents: producer consumer example

252 views
Skip to first unread message

Parth Malwankar

unread,
Aug 21, 2008, 8:47:40 AM8/21/08
to Clojure
Hello,

I created a simple example of two producer and consumer
agent and this works fine from the repl. However, if I run
it from the command line nothing seems to happen.
Am I doing anything wrong here?

user=> (load-file "agents.clj")
clojure.lang.Agent@10e7c9e
user=> producer: [12]
consumer: 12
consumer: nilproducer:
[48]
consumer: producer: 48[
2]
producer: [2 59]
consumer: 59
producer: [2 61]
consumer: 61
consumer: 2
producer: [0]
producer: [0 67]
consumer: 67
consumer: producer: 0[
71]
producer: [71 92]
consumer: 92
[parth:~/training/clj]% clj agents.clj <--- nothing happens so I Ctrl
+C
[parth:~/training/clj]%

Is there a better way to do this? Code below.

Thanks.
Parth

(load-file "/home/parth/src/clojure-contrib/dist/clojure/contrib/pred/
pred.clj")
(alias 'pred 'clojure.contrib.pred)

(def *sleep-time-ms* 1000)

(defn sleep [n]
(. Thread (sleep n)))

(def cell (ref []))

(defn cell-push []
(dosync
(commute cell conj (rand-int 99))))

(defn cell-pop []
(dosync
(let [data (last @cell)]
(when (not (pred/empty? @cell))
(ref-set cell (pop @cell)))
data)))

(def producer-agent (agent nil))
(def consumer-agent (agent nil))

(defn producer [x]
(send-off *agent* (var producer))
(sleep *sleep-time-ms*)
(println "producer: " (cell-push)))

(defn consumer [x]
(send-off *agent* (var consumer))
(sleep *sleep-time-ms*)
(println "consumer: " (cell-pop)))

(send-off producer-agent producer)
(send-off consumer-agent consumer)

Chouser

unread,
Aug 21, 2008, 10:00:35 AM8/21/08
to clo...@googlegroups.com
On Thu, Aug 21, 2008 at 8:47 AM, Parth Malwankar
<parth.m...@gmail.com> wrote:
>
> I created a simple example of two producer and consumer
> agent and this works fine from the repl. However, if I run
> it from the command line nothing seems to happen.
> Am I doing anything wrong here?

Not really. The difference is between using the Repl and Script
classes. Repl, after running your code, hangs around indefinitely
with the input and output stream open, waiting for you to type more
expressions. Script, after running your code, flushes and closes the
output stream.

It really comes down to your exit case -- when do you want your
program to quit? Right now it never ends. If you make that explicit
before the end of your .clj file, you'll probably see what you were
expecting. For example, you could add this to the end:

(doseq x (repeatedly #(Thread/sleep 100)))

In a "real" program you'd probably want a more clever exit case --
after a certain number of items have been consumed, when a certain
event occurs, or whatever.

By the way, if this isn't just for practice with agents, some of the
functionality you've produced is already available with seque:

(def producer
(seque 1 (repeatedly #(let [i (rand-int 99)]
(println "producer:" i)
i))))

(doseq o (take 10 producer)
(println "consumer:" o)
(Thread/sleep 1000))

--Chouser

Parth Malwankar

unread,
Aug 21, 2008, 10:58:44 AM8/21/08
to Clojure


On Aug 21, 7:00 pm, Chouser <chou...@gmail.com> wrote:
> On Thu, Aug 21, 2008 at 8:47 AM, Parth Malwankar
>
> <parth.malwan...@gmail.com> wrote:
>
> > I created a simple example of two producer and consumer
> > agent and this works fine from the repl. However, if I run
> > it from the command line nothing seems to happen.
> > Am I doing anything wrong here?
>
> Not really.  The difference is between using the Repl and Script
> classes.  Repl, after running your code, hangs around indefinitely
> with the input and output stream open, waiting for you to type more
> expressions.  Script, after running your code, flushes and closes the
> output stream.
>
> It really comes down to your exit case -- when do you want your
> program to quit?  Right now it never ends.  If you make that explicit
> before the end of your .clj file, you'll probably see what you were
> expecting.  For example, you could add this to the end:
>
> (doseq x (repeatedly #(Thread/sleep 100)))

Works perfectly. Thanks.

A somewhat related question. Is it possible to know if we are
running in repl or as a script?

So for example is it possible to do something like this at
the end of file:

(when (running-as-script)
(doseq x (repeatedly #(Thread/sleep 100))))

>
> In a "real" program you'd probably want a more clever exit case --
> after a certain number of items have been consumed, when a certain
> event occurs, or whatever.
>
> By the way, if this isn't just for practice with agents, some of the
> functionality you've produced is already available with seque:
>
> (def producer
>   (seque 1 (repeatedly #(let [i (rand-int 99)]
>                           (println "producer:" i)
>                           i))))
>
> (doseq o (take 10 producer)
>   (println "consumer:" o)
>   (Thread/sleep 1000))

This was just practice but the above approach seems very
interesting. Will try this also.
Is 'seque' a relatively new addition to Clojure? I could find the
docs on clojure.org ... or may I just didn't look hard enough.

>
> --Chouser

Chouser

unread,
Aug 21, 2008, 11:25:38 AM8/21/08
to clo...@googlegroups.com
On Thu, Aug 21, 2008 at 10:58 AM, Parth Malwankar
<parth.m...@gmail.com> wrote:
>
> Works perfectly. Thanks.
>
> A somewhat related question. Is it possible to know if we are
> running in repl or as a script?
>
> So for example is it possible to do something like this at
> the end of file:
>
> (when (running-as-script)
> (doseq x (repeatedly #(Thread/sleep 100))))

I don't know of any such test, but I don't think it's generally
needed. If this is your whole app, there's no real benefit in having
both the producer and consumer running in the non-main thread. For
example if you put the consumer in the main thread by just evaluating
it directly instead of using send-off, then that allow it work equally
well in the Repl and the Script.

Sleeping forever at the end of the script is not really a great
solution. I probably shouldn't have suggested it. :-)

> Is 'seque' a relatively new addition to Clojure? I could find the
> docs on clojure.org ... or may I just didn't look hard enough.

Added July 3rd. The online docs do tend to lag a bit.

--Chouser

Drew Raines

unread,
Nov 12, 2008, 4:19:01 PM11/12/08
to clo...@googlegroups.com
Parth Malwankar wrote:

> So for example is it possible to do something like this at
> the end of file:
>
> (when (running-as-script)
> (doseq x (repeatedly #(Thread/sleep 100))))

I do it with this idiom:

(when *command-line-args*
...)

Check out Script.java for more info.

-Drew

Reply all
Reply to author
Forward
0 new messages