1. 程式人生 > 其它 >併發程式設計模型3:協程

併發程式設計模型3:協程

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)