博客 / 詳情

返回

用rust寫lisp解釋器2 (實現一個簡單的異步模型(channel + thread => go))

背景

前段時間實現了一個 call-with-tcp-listener 過程(函數)

 (call-with-tcp-listener "127.0.0.1:8088" ( lambda (in) (
      (display  (req-read-string in))
      "HTTP/1.1 200 OK\r\n\r\n hello word"
 )))

如果是簡單的返回數據還不存在問題,但是當涉及到io的時候就會出現阻塞的情況,最簡單的解決方案就是一個請求一個線程,但是這種模型開銷比較大,所以想到了線程池,然後就實現了一個很簡單的版本

實現

使用到了 thread + channel + lambda-lep + apply 這幾個過程
首先定義一個線程池
async.lisp

(
    (define thread-qty (* (get-os-cpu-num) 2))
    (define thread-count 1)
    (define barrier (make-barrier thread-qty))
    (define channel (make-channel))
    (while (<  thread-count thread-qty)
        (  
            (thread-run (lambda () (
                (channel-for-each (lambda (task) (
                    ( task)
                )) channel)
                (barrier-wait barrier)
                ;; (loop ((<- channel)))
            )))
            (set! thread-count (+ thread-count 1))))
    (def go (task) (
       (apply (`(-> ,channel ,task)))
    ))
    (export go)
)

如何使用


(
    (import (go) from "./async.lisp")
    (go 
        (lambda () 
            (println (current-thread-name) " hello rust-lisp!"))))

控制枱會輸出

thread-1 hello rust-lisp!

重構

讓我們在結合 call-with-tcp-listener 過程完善一下吧
首先重構一下 call-with-tcp-listener 過程使其接受out port
main.lisp

(
    (def handler (in out) (
        ;; 模擬io讀取等待
        (sleep 1)
        (println (current-thread-name))
        (display  (req-read-string in))
        (write-string "HTTP/1.1 200 OK\r\n\r\n hello word" out )
    ))
    (call-with-tcp-listener "127.0.0.1:8088" ( lambda (in out) (
         ( handler in out)
    ))))

然後使用go 過程實現任務提交
main.lisp

(
    (load "./lib.lisp")
    (import (go) from "./async.lisp")
    (def handler (in out) (
        ;; 模擬io讀取等待
        (sleep 1)
        (println (current-thread-name))
        (display  (req-read-string in))
        (write-string "HTTP/1.1 200 OK\r\n\r\n hello word" out )
    ))
    (call-with-tcp-listener "127.0.0.1:8088" ( lambda (in out) (
         (go (lambda () (handler in out)))
    ))))

任務提交之後,下面這段代碼會從channel中讀取到最新提交的 task (過程) 然後執行。

(channel-for-each (lambda (task) (
                    (task)
                )) channel)

運行後訪問 控制枱打印如下

thread1
GET / HTTP/1.0
Host: 127.0.0.1:8088
User-Agent: ApacheBench/2.3
Accept: */*

async.lisp 源碼

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.