Added taskvent.lisp, taskwork.lisp and tasksink.lisp examples. Updated
build scripts.


-- 
--ska
From e0632b7c40fe207df89dda40a5032cb2dbab293d Mon Sep 17 00:00:00 2001
From: Kamil Shakirov <kamil...@gmail.com>
Date: Mon, 4 Oct 2010 14:39:41 +0700
Subject: [PATCH] Add taskvent.lisp, taskwork.lisp and tasksink.lisp examples.

---
 examples/C/.gitignore              |    3 +
 examples/Common Lisp/.gitignore    |    4 ++
 examples/Common Lisp/build         |    2 +-
 examples/Common Lisp/build.lisp    |   16 +++++-
 examples/Common Lisp/compile       |    6 +-
 examples/Common Lisp/hwclient.lisp |    8 ++--
 examples/Common Lisp/hwserver.lisp |    4 +-
 examples/Common Lisp/tasksink.lisp |   65 ++++++++++++++++++++++----
 examples/Common Lisp/taskvent.lisp |   52 +++++++++++++++++----
 examples/Common Lisp/taskwork.lisp |   53 +++++++++++++++++----
 examples/Common Lisp/wuclient.lisp |   10 ++--
 examples/Common Lisp/wuserver.lisp |    3 -
 examples/Common Lisp/zhelpers.lisp |   88 +++++++++++++++++++++++++++++-------
 13 files changed, 247 insertions(+), 67 deletions(-)

diff --git a/examples/C/.gitignore b/examples/C/.gitignore
index 2335456..44f149d 100644
--- a/examples/C/.gitignore
+++ b/examples/C/.gitignore
@@ -1,4 +1,7 @@
+core
 *.o
+*.lst
+
 hwclient
 hwserver
 msgqueue
diff --git a/examples/Common Lisp/.gitignore b/examples/Common Lisp/.gitignore
index 23d0a05..85f8a80 100644
--- a/examples/Common Lisp/.gitignore	
+++ b/examples/Common Lisp/.gitignore	
@@ -1,5 +1,8 @@
 # ignore file
 
+/tasksink
+/taskvent
+/taskwork
 /hwclient
 /hwserver
 /wuclient
@@ -7,3 +10,4 @@
 /zversion
 
 *.fas*
+*.*fsl
diff --git a/examples/Common Lisp/build b/examples/Common Lisp/build
index 8b415fd..95aa989 100755
--- a/examples/Common Lisp/build	
+++ b/examples/Common Lisp/build	
@@ -10,7 +10,7 @@ if [ /$1/ = /all/ ]; then
     done
 elif [ /$1/ = /clean/ ]; then
     echo "Cleaning Common Lisp examples directory..."
-    rm -f *.fas* core
+    rm -f *.fas* *.*fsl core
     for MAIN in `egrep -l main *.lisp`; do
         rm -f `basename $MAIN .lisp`
     done
diff --git a/examples/Common Lisp/build.lisp b/examples/Common Lisp/build.lisp
index 5b7e89d..0eec089 100644
--- a/examples/Common Lisp/build.lisp	
+++ b/examples/Common Lisp/build.lisp	
@@ -5,6 +5,12 @@
 ;;; Kamil Shakirov <kamil...@gmail.com>
 ;;;
 
+(in-package :cl-user)
+
+(eval-when (:compile-toplevel :load-toplevel :execute)
+  (require :split-sequence)
+  (require :zeromq))
+
 (defpackage #:zguide.build
   (:nicknames #:build)
   (:use #:cl)
@@ -13,6 +19,10 @@
 
 (in-package :zguide.build)
 
-(defun build (app-name app-entry)
-  #+sbcl (sb-ext:save-lisp-and-die app-name :executable t :toplevel app-entry)
-  #+ccl (ccl:save-application app-name :prepend-kernel t :toplevel-function app-entry))
+(defun build (app-name)
+  (load (compile-file "zhelpers"))
+  (load (compile-file app-name))
+
+  (let ((app-entry (find-symbol "MAIN" (string-upcase app-name))))
+    #+sbcl (sb-ext:save-lisp-and-die app-name :executable t :toplevel app-entry)
+    #+ccl (ccl:save-application app-name :prepend-kernel t :toplevel-function app-entry)))
diff --git a/examples/Common Lisp/compile b/examples/Common Lisp/compile
index 0000fc0..9bc7162 100755
--- a/examples/Common Lisp/compile	
+++ b/examples/Common Lisp/compile	
@@ -11,10 +11,10 @@ LISP_OPTS=
 
 case $LISP in
     sbcl)
-        LISP_OPTS="--load build.lisp --load zhelpers.lisp --load $1.lisp --eval"
+        LISP_OPTS="--load build.lisp --eval"
         ;;
     ccl)
-        LISP_OPTS="--load build.lisp --load zhelpers.lisp --load $1.lisp --eval"
+        LISP_OPTS="--load build.lisp --eval"
         ;;
     *)
         echo "'LISP=$LISP' is not supported!"
@@ -22,4 +22,4 @@ case $LISP in
         ;;
 esac
 
-$LISP $LISP_OPTS "(build:build \"$1\" #'$1:main)"
+$LISP $LISP_OPTS "(build:build \"$1\")"
diff --git a/examples/Common Lisp/hwclient.lisp b/examples/Common Lisp/hwclient.lisp
index e0d005f..3a71925 100644
--- a/examples/Common Lisp/hwclient.lisp	
+++ b/examples/Common Lisp/hwclient.lisp	
@@ -18,19 +18,19 @@
   ;; Prepare our context and socket
   (zmq:with-context (context 1)
     (zmq:with-socket (socket context zmq:req)
-      (format t "Connecting to hello world server...~%")
+      (message "Connecting to hello world server...~%")
       (zmq:connect socket "tcp://localhost:5555")
 
       ;; Do 10 requests, waiting each time for a response
       (dotimes (request-nbr 10)
         (let ((request (make-instance 'zmq:msg :data "Hello")))
-          (format t "Sending request ~D...~%" request-nbr)
+          (message "Sending request ~D...~%" request-nbr)
           (zmq:send socket request))
 
         ;; Get the reply
         (let ((response (make-instance 'zmq:msg)))
           (zmq:recv socket response)
-          (format t "Received reply ~D: [~A]~%"
-                  request-nbr (zmq:msg-data-as-string response))))))
+          (message "Received reply ~D: [~A]~%"
+                   request-nbr (zmq:msg-data-as-string response))))))
 
   (cleanup))
diff --git a/examples/Common Lisp/hwserver.lisp b/examples/Common Lisp/hwserver.lisp
index 3371905..6bb4cef 100644
--- a/examples/Common Lisp/hwserver.lisp	
+++ b/examples/Common Lisp/hwserver.lisp	
@@ -24,8 +24,8 @@
         (let ((request (make-instance 'zmq:msg)))
           ;; Wait for next request from client
           (zmq:recv socket request)
-          (format t "Received request: [~A]~%"
-                  (zmq:msg-data-as-string request))
+          (message "Received request: [~A]~%"
+                   (zmq:msg-data-as-string request))
 
           ;; Do some 'work'
           (sleep 1)
diff --git a/examples/Common Lisp/tasksink.lisp b/examples/Common Lisp/tasksink.lisp
index 5a2b8fa..8b17a63 100644
--- a/examples/Common Lisp/tasksink.lisp	
+++ b/examples/Common Lisp/tasksink.lisp	
@@ -1,13 +1,58 @@
-No-one has translated the tasksink example into Common Lisp yet.  Be the first to create
-tasksink in Common Lisp and get one free Internet!  If you're the author of the Common Lisp
-binding, this is a great way to get people to use 0MQ in Common Lisp.
+;;; -*- Mode:Lisp; Syntax:ANSI-Common-Lisp; -*-
+;;;
+;;;  Task sink
+;;;  Binds PULL socket to tcp://localhost:5558
+;;;  Collects results from workers via that socket
+;;;
+;;; 'with-stopwatch' macro is taken from 'cl-zmq'
+;;; by Vitaly Mayatskikh <v.mayats...@gmail.com>
+;;;
+;;; Kamil Shakirov <kamil...@gmail.com>
+;;;
 
-To submit a new translation email it to zeromq-...@lists.zeromq.org.  Please:
+(defpackage #:zguide.tasksink
+  (:nicknames #:tasksink)
+  (:use #:cl #:zhelpers)
+  (:export #:main))
 
-* Stick to identical functionality and naming used in examples so that readers
-  can easily compare languages.
-* You MUST place your name as author in the examples so readers can contact you.
-* You MUST state in the email that you license your code under the MIT/X11
-  license.
+(in-package :zguide.tasksink)
 
-Subscribe to this list at http://lists.zeromq.org/mailman/listinfo/zeromq-dev.
+(defmacro with-stopwatch (&body body)
+  (let ((sec0 (gensym))
+        (sec1 (gensym))
+        (usec0 (gensym))
+        (usec1 (gensym)))
+    `(multiple-value-bind (,sec0 ,usec0)
+         (isys:gettimeofday)
+       (unwind-protect
+            (progn ,@body))
+       (multiple-value-bind (,sec1 ,usec1)
+           (isys:gettimeofday)
+         (+ (* 1e6 (- ,sec1 ,sec0))
+            ,usec1 (- ,usec0))))))
+
+(defun main ()
+  ;; Prepare our context and socket
+  (zmq:with-context (context 1)
+    (zmq:with-socket (receiver context zmq:pull)
+      (zmq:bind receiver "tcp://*:5558")
+
+      ;; Wait for start of batch
+      (let ((msg (make-instance 'zmq:msg)))
+        (zmq:recv receiver msg)
+        (let ((string (zmq:msg-data-as-string msg)))
+          ;; Start our clock now
+          (let ((elapsed-time
+                 (with-stopwatch
+                   (dotimes (task-nbr 100)
+                     (zmq:recv receiver msg)
+                     (setf string (zmq:msg-data-as-string msg))
+
+                     (if (= 1 (denominator (/ task-nbr 10)))
+                         (message ":")
+                         (message "."))))))
+
+            ;; Calculate and report duration of batch
+            (message "Total elapsed time: ~F msec~%" (/ elapsed-time 1000.0)))))))
+
+  (cleanup))
diff --git a/examples/Common Lisp/taskvent.lisp b/examples/Common Lisp/taskvent.lisp
index 0b49d2d..1f344ad 100644
--- a/examples/Common Lisp/taskvent.lisp	
+++ b/examples/Common Lisp/taskvent.lisp	
@@ -1,13 +1,45 @@
-No-one has translated the taskvent example into Common Lisp yet.  Be the first to create
-taskvent in Common Lisp and get one free Internet!  If you're the author of the Common Lisp
-binding, this is a great way to get people to use 0MQ in Common Lisp.
+;;; -*- Mode:Lisp; Syntax:ANSI-Common-Lisp; -*-
+;;;
+;;;  Task ventilator
+;;;  Binds PUSH socket to tcp://localhost:5557
+;;;  Sends batch of tasks to workers via that socket
+;;;
+;;; Kamil Shakirov <kamil...@gmail.com>
+;;;
 
-To submit a new translation email it to zeromq-...@lists.zeromq.org.  Please:
+(defpackage #:zguide.taskvent
+  (:nicknames #:taskvent)
+  (:use #:cl #:zhelpers)
+  (:export #:main))
 
-* Stick to identical functionality and naming used in examples so that readers
-  can easily compare languages.
-* You MUST place your name as author in the examples so readers can contact you.
-* You MUST state in the email that you license your code under the MIT/X11
-  license.
+(in-package :zguide.taskvent)
 
-Subscribe to this list at http://lists.zeromq.org/mailman/listinfo/zeromq-dev.
+(defun main ()
+  (zmq:with-context (context 1)
+    ;; Socket to send messages on
+    (zmq:with-socket (sender context zmq:push)
+      (zmq:bind sender "tcp://*:5557")
+
+      (message "Press Enter when the workers are ready: ")
+      (read-char)
+      (message "Sending tasks to workers...~%")
+
+      ;; The first message is "0" and signals start of batch
+      (let ((msg (make-instance 'zmq:msg :data "0")))
+        (zmq:send sender msg))
+
+      ;; Send 100 tasks
+      (let ((total-msec 0))
+        (loop :repeat 100 :do
+          ;; Random workload from 1 to 100 msecs
+          (let ((workload (within 100)))
+            (incf total-msec workload)
+            (let ((msg (make-instance 'zmq:msg
+                                      :data (format nil "~D" workload))))
+              (zmq:send sender msg))))
+
+        (message "Total expected cost: ~D msec~%" total-msec)
+        ;; Give 0MQ time to deliver
+        (sleep 1))))
+
+  (cleanup))
diff --git a/examples/Common Lisp/taskwork.lisp b/examples/Common Lisp/taskwork.lisp
index 0b600b9..feb1c21 100644
--- a/examples/Common Lisp/taskwork.lisp	
+++ b/examples/Common Lisp/taskwork.lisp	
@@ -1,13 +1,46 @@
-No-one has translated the taskwork example into Common Lisp yet.  Be the first to create
-taskwork in Common Lisp and get one free Internet!  If you're the author of the Common Lisp
-binding, this is a great way to get people to use 0MQ in Common Lisp.
+;;; -*- Mode:Lisp; Syntax:ANSI-Common-Lisp; -*-
+;;;
+;;;  Task worker
+;;;  Connects PULL socket to tcp://localhost:5557
+;;;  Collects workloads from ventilator via that socket
+;;;  Connects PUSH socket to tcp://localhost:5558
+;;;  Sends results to sink via that socket
+;;;
+;;; Kamil Shakirov <kamil...@gmail.com>
+;;;
 
-To submit a new translation email it to zeromq-...@lists.zeromq.org.  Please:
+(defpackage #:zguide.taskwork
+  (:nicknames #:taskwork)
+  (:use #:cl #:zhelpers)
+  (:export #:main))
 
-* Stick to identical functionality and naming used in examples so that readers
-  can easily compare languages.
-* You MUST place your name as author in the examples so readers can contact you.
-* You MUST state in the email that you license your code under the MIT/X11
-  license.
+(in-package :zguide.taskwork)
 
-Subscribe to this list at http://lists.zeromq.org/mailman/listinfo/zeromq-dev.
+(defun main ()
+  (zmq:with-context (context 1)
+    ;; Socket to receive messages on
+    (zmq:with-socket (receiver context zmq:pull)
+      (zmq:connect receiver "tcp://localhost:5557")
+
+      ;; Socket to send messages to
+      (zmq:with-socket (sender context zmq:push)
+        (zmq:connect sender "tcp://localhost:5558")
+
+        ;; Process tasks forever
+        (loop
+          (let ((pull-msg (make-instance 'zmq:msg)))
+            (zmq:recv receiver pull-msg)
+
+            (let* ((string (zmq:msg-data-as-string pull-msg))
+                   (delay (* (parse-integer string) 1000)))
+              ;; Simple progress indicator for the viewer
+              (message "~A." string)
+
+              ;; Do the work
+              (isys:usleep delay)
+
+              ;; Send results to sink
+              (let ((push-msg (make-instance 'zmq:msg :data "")))
+                (zmq:send sender push-msg))))))))
+
+  (cleanup))
diff --git a/examples/Common Lisp/wuclient.lisp b/examples/Common Lisp/wuclient.lisp
index e60bc32..778dde0 100644
--- a/examples/Common Lisp/wuclient.lisp	
+++ b/examples/Common Lisp/wuclient.lisp	
@@ -16,21 +16,21 @@
 
 (defun main ()
   (zmq:with-context (context 1)
-    (format t "Collecting updates from weather server...~%")
+    (message "Collecting updates from weather server...~%")
 
     ;; Socket to talk to server
     (zmq:with-socket (subscriber context zmq:sub)
       (zmq:connect subscriber "tcp://localhost:5556")
 
       ;; Subscribe to zipcode, default is NYC, 10001
-      (let ((filter (or (nth 1 (cmd-args)) "10001")))
+      (let ((filter (or (first (cmd-args)) "10001 ")))
         (zmq:setsockopt subscriber zmq:subscribe filter)
 
         ;; Process 100 updates
         (let ((number-updates 100)
               (total-temp 0.0))
 
-          (dotimes (update-nbr number-updates)
+          (loop :repeat number-updates :do
             (let ((update (make-instance 'zmq:msg)))
               (zmq:recv subscriber update)
 
@@ -40,7 +40,7 @@
                 (declare (ignore zipcode_ relhumidity_))
                 (incf total-temp (parse-integer temperature)))))
 
-          (format t "Average temperature for zipcode ~A was ~FF~%"
-                  filter (/ total-temp number-updates))))))
+          (message "Average temperature for zipcode ~A was ~FF~%"
+                   filter (/ total-temp number-updates))))))
 
   (cleanup))
diff --git a/examples/Common Lisp/wuserver.lisp b/examples/Common Lisp/wuserver.lisp
index a8b2637..f0b2dae 100644
--- a/examples/Common Lisp/wuserver.lisp	
+++ b/examples/Common Lisp/wuserver.lisp	
@@ -14,9 +14,6 @@
 
 (in-package :zguide.wuserver)
 
-(defun within (num)
-  (1+ (random num)))
-
 (defun main ()
   ;; Prepare our context and socket
   (zmq:with-context (context 1)
diff --git a/examples/Common Lisp/zhelpers.lisp b/examples/Common Lisp/zhelpers.lisp
index 61373ef..1722439 100644
--- a/examples/Common Lisp/zhelpers.lisp	
+++ b/examples/Common Lisp/zhelpers.lisp	
@@ -5,24 +5,38 @@
 ;;; Kamil Shakirov <kamil...@gmail.com>
 ;;;
 
-(eval-when (:compile-toplevel :load-toplevel :execute)
-  (require :split-sequence)
-  (require :zeromq))
-
 (defpackage #:zguide.zhelpers
   (:nicknames #:zhelpers)
   (:use #:cl)
   (:export
-   #:version
+   #:cmd-args
+   #:message
    #:cleanup
-   #:cmd-args))
+   #:within
+   #:version
+   #:set-socket-id
+   #:dump-message
+   #:dump-socket))
 
 (in-package :zguide.zhelpers)
 
-(defun version ()
-  (format t "Current 0MQ version is ~A~%" (zmq:version)))
+(defun cmd-args ()
+  "Return command line arguments."
+  (rest
+   (or
+    #+sbcl sb-ext:*posix-argv*
+    #+ccl ccl:*command-line-argument-list*
+    #+clisp ext:*args*
+    #+lispworks system:*line-arguments-list*
+    #+ecl (ext:command-args)
+    nil)))
+
+(defun message (fmt &rest args)
+  (apply #'format t fmt args)
+  (finish-output))
 
 (defun cleanup ()
+  "Cleanup and exit."
   (tg:gc)
   #+sbcl (sb-ext:quit)
   #+ccl (ccl:quit)
@@ -30,11 +44,53 @@
   #+lispworks (lispworks:quit)
   #+ecl (ext:quit))
 
-(defun cmd-args ()
-  (or
-   #+sbcl sb-ext:*posix-argv*
-   #+ccl ccl:*command-line-argument-list*
-   #+clisp ext:*args*
-   #+lispworks system:*line-arguments-list*
-   #+ecl (ext:command-args)
-   nil))
+(defun within (num)
+  "Provide random number from 1..num."
+  (1+ (random num)))
+
+(defun version ()
+  "Report 0MQ version number."
+  (message "Current 0MQ version is ~A~%" (zmq:version)))
+
+(defun set-socket-id (socket)
+  "Set simple random printable identity on socket."
+  (zmq:setsockopt socket zmq:identity
+                  (format nil "~4,'0X-~4,'0X"
+                          (within #x10000) (within #x10000))))
+
+(defun text-message-p (msg)
+  (let ((data (zmq:msg-data-as-is msg)))
+    (loop :for i :from 0 :to (1- (zmq:msg-size msg))
+          :with char = (cffi:mem-ref data :char i) :do
+      (when (or (< char 32) (> char 127))
+        (return-from text-message-p nil)))
+    (values t)))
+
+(defun dump-binary-message (msg)
+  (let ((data (zmq:msg-data-as-array msg)))
+    (loop :for x :across data :do
+      (format t "~2,'0X" x))))
+
+(defun dump-message (msg)
+  (format t "[~3,'0D] " (zmq:msg-size msg))
+  (if (text-message-p msg)
+      (write-string (zmq:msg-data-as-string msg))
+      (dump-binary-message msg))
+  (terpri))
+
+(defun dump-socket (socket)
+  "Receive all message parts from socket, print neatly."
+  (format t "----------------------------------------~%")
+
+  (loop
+    ;; Process all parts of the message
+   (let ((message (make-instance 'zmq:msg)))
+     (zmq:recv socket message)
+
+     ;; Dump the message as text or binary
+     (dump-message message)
+     (finish-output)
+
+     ;; Multipart detection
+     (when (zerop (zmq:getsockopt socket zmq:rcvmore))
+       (return)))))
-- 
1.7.0.4

_______________________________________________
zeromq-dev mailing list
zeromq-dev@lists.zeromq.org
http://lists.zeromq.org/mailman/listinfo/zeromq-dev

Reply via email to