第五部分-并发编程模型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)
posted @ 2021-06-22 18:20  SpecialSpeculator  阅读(66)  评论(0编辑  收藏  举报