Go语言并发笔记

在Go语言中有着两种并发风格,通信顺序进程CSP和共享内存。 在Go语言中,通过关键字 go即可创建一个goroutine “`go foo() //调用foo()函数,阻塞 go foo() // 新建一个goroutine调用foo(),非阻塞


当一个程序启动时,只有一个主goroutine调用main函数,当main函数返回时,所以的goroutine都会直接终结,程序退出。
# 关键词go
## 非并发处理TCP请求
下面是一段向客户端发送时间的代码


```go
package main

import (
	"io"
	"log"
	"net"
	"time"
)

func main() {
    // 监听端口
	listener, err := net.Listen("tcp", "localhost:8000")
	if err != nil {
		log.Fatal(err)
	}
	for {
        // 阻塞等待接受新的连接请求
		conn, err := listener.Accept()
		if err != nil {
			log.Print(err) // e.g., connection aborted
			continue
		}
        // 处理请求
		handleConn(conn) // handle one connection at a time
	}
}

func handleConn(c net.Conn) {
	defer c.Close()
	for {
        // 返回现在的时间
		_, err := io.WriteString(c, time.Now().Format("15:04:05\n"))
		if err != nil {
			return // e.g., client disconnected
		}
        // 过一秒继续返回时间
		time.Sleep(1 * time.Second)
	}
}

测试客户端可以使用netcat shell nc localhost 8000

并发处理TCP请求

想要并发处理请求,加上go关键词即可。

“`go for { // 阻塞等待接受新的连接请求 conn, err := listener.Accept() if err != nil { log.Print(err) // e.g., connection aborted continue } // 创建goroutine处理请求 go handleConn(conn) }



# 通道
goroutine->并发的执行体,通道(channel)->连接goroutine,通过通道可以在goroutine之间传递消息,每种通道都有通道的元素类型,如`chan int`是`int`类型的通道。
使用`make`函数可以创建一个通道:


```go
ch := make(chan int)

当我们复制或作为参数传递通道时,传递的都是引用。通道的零值是nil,是一种引用类型。 通道有两种操作,发送和接受。

go ch <- x // 发送x x = <- ch // 接收到x <-ch // 接收值,常用于同步 通道支持关闭,通过close(ch)可以关闭一个通道。

无缓冲通道

通过简单的make调用就可以创建一个无缓冲的通道。在无缓冲的通道上,发送操作会被阻塞,直到另一处接受值,这种通道可以用来同步。

go func main() { conn, err := net.Dial("tcp", "localhost:8000") if err != nil { log.Fatal(err) } done := make(chan struct{}) go func() { io.Copy(os.Stdout, conn) // NOTE: ignoring errors log.Println("done") done <- struct{}{} // signal the main goroutine }() mustCopy(conn, os.Stdin) conn.Close() <-done // wait for background goroutine to finish } func mustCopy(dst io.Writer, src io.Reader) { if _, err := io.Copy(dst, src); err != nil { log.Fatal(err) } }