併發程式設計模型3:協程
阿新 • • 發佈:2021-06-22
1.協程
輕量級執行緒
Coroutine
執行緒是核心態排程的,協程是使用者態排程的,使用者態排程的資源消耗更小,效能更高
核心態使用者態之間切換有成本
執行緒的棧大小:1M
協程的棧大小:幾K或者幾十K
2.Golang中的協程示例
import ( "fmt" "time" ) func hello(msg string) { fmt.Println("Hello " + msg) } func main() { //在新的協程中執行hello方法 go hello("World") fmt.Println("Run in main") //等待100毫秒讓協程執行結束 time.Sleep(100 * time.Millisecond) }
3.Golang中應用Thread-Pre-Message模式
一個請求,開一個協程
import ( "log" "net" ) func main() { //監聽本地9090埠 socket, err := net.Listen("tcp", "127.0.0.1:9090") if err != nil { log.Panicln(err) } defer socket.Close() for { //處理連線請求 conn, err := socket.Accept() if err != nil { log.Panicln(err) } //處理已經成功建立連線的請求 go handleRequest(conn) } } //處理已經成功建立連線的請求 func handleRequest(conn net.Conn) { defer conn.Close() for { buf := make([]byte, 1024) //讀取請求資料 size, err := conn.Read(buf) if err != nil { return } //回寫相應資料 conn.Write(buf[:size]) } }
4.協程實現非同步轉同步
在 Java 裡使用多執行緒併發地處理 I/O,基本上用的都是非同步非阻塞模型,這種模型的非同步主要是靠註冊回撥函式實現的,那能否都使用同步處理呢?顯然是不能的。因為同步意味著等待,而執行緒等待,本質上就是一種嚴重的浪費。不過對於協程來說,等待的成本就沒有那麼高了,所以基於協程實現同步非阻塞是一個可行的方案。
同步非阻塞程式碼範例,來源於openresty
-- 建立socket local sock = ngx.socket.tcp() -- 設定socket超時時間 sock:settimeouts(connect_timeout, send_timeout, read_timeout) -- 連線到目標地址 local ok, err = sock:connect(host, port) if not ok then - -- 省略異常處理 end -- 傳送請求 local bytes, err = sock:send(request_data) if not bytes then -- 省略異常處理 end -- 讀取響應 local line, err = sock:receive() if err then -- 省略異常處理 end -- 關閉socket sock:close() -- 處理讀取到的資料line handle(line)