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)
}
}