背景
前段時間實現了一個 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 源碼