Common Lisp中的并发编程

Rob Pike谈到了Go语言中的并发编程,其主旨是在分开的轻量级进程中启动并发的任务,任务通过channel通信来同步。Common Lisp中的ChanL库提供了类似的功能,尽管我不知道其线程如何轻量,但其接口是相似的。


使用channel简单有效的例子是并行执行一些IO相关的任务,比如取多个网页。开始前,先定义一个计时的宏:

(defmacro time-it (&body body)
    (let ((start-time (gensym)))
      `(let ((,start-time (get-internal-real-time)))
          ,@body
         (format t "Runtime: ~a milliseconds.~%" (- (get-internal-real-time) ,start-time)))))

接着使用QuickLisp装入ChanL与Drakma(用于简单的HTTP requests):
(ql:quickload "drakma")
(ql:quickload "chanl")

URLs例子:
(defparameter *urls*
    (list
        "http://blog.thezerobit.com/"
        "http://quicklisp.org/"
        "http://www.cliki.net/index"
        "http://sbcl.org/"))

一个执行简单HTTP request的函数:
(defun do-request (url)
    (let ((start-time (get-internal-real-time)))
        (format t "Starting request: ~a~%" url)
        (drakma:http-request url)
        (let ((elapsed (- (get-internal-real-time) start-time)))
            (format t "Completed request in ~a ms: ~a~%" elapsed url))))

没有使用并发的做法:
(time-it (dolist (url *urls*) (do-request url)))


;; Starting request: http://blog.thezerobit.com/
;; Completed request in 616 ms: http://blog.thezerobit.com/
;; Starting request: http://quicklisp.org/
;; Completed request in 819 ms: http://quicklisp.org/
;; Starting request: http://www.cliki.net/index
;; Completed request in 429 ms: http://www.cliki.net/index
;; Starting request: http://sbcl.org/
;; Completed request in 291 ms: http://sbcl.org/
;; Runtime: 2155 milliseconds.

以串行的方式完成所有requests要超过2秒。


(defun do-request-chan (url chan)
    (let ((start-time (get-internal-real-time)))
        (
chanl:send chan (formatnil "Starting request: ~a~%" url))
        (drakma:http-request url)
        (let ((elapsed (- (get-internal-real-time) start-time)))
           (
chanl:sendchan
                (format
nil "Completed request in ~a ms: ~a~%" elapsed url)))))

对于每个HTTP request,我们调用
pexec启动分开的进程,然后等待8条消息进入为同步而创建的channel。

(time-it
    (let ((chan (make-instance'chanl:channel)))
        (dolist (url *urls*)
            (chanl:pexec () (do-request-chan url chan)))
        (dotimes (x 8)
           (format t (chanl:recv chan)))))

;; Starting request: http://blog.thezerobit.com/
;; Starting request: http://quicklisp.org/
;; Starting request: http://sbcl.org/
;; Starting request: http://www.cliki.net/index
;; Completed request in 291 ms: http://blog.thezerobit.com/
;; Completed request in 302 ms: http://www.cliki.net/index
;; Completed request in 306 ms: http://sbcl.org/
;; Completed request in 703 ms: http://quicklisp.org/
;; Runtime: 703 milliseconds.

整个操作仅花费了那个最长request的时间,创建线程的开销与并发节约的时间相比可以忽略。注意,缺省情况下channels不缓存,因此send将阻塞到有其它线程调用recv为止。ChanL也提供了带缓存的channels和其它一些goodies,有兴趣的可以自己研究。


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值