Go 并发学习笔记

什么是Go并发?

Go并发是指在同一时间内执行多个线程或任务的能力。Go语言使用goroutines和channels机制来实现并发。

goroutines

goroutine是轻量级的线程,由Go运行时管理。与线程相比,它们拥有更小的堆栈大小(一般为2KB)并且更加高效。在Go程序中启动一个goroutine非常简单,只需要在函数调用前加上关键字go即可。

goCopy Code
func main() { go func() { // 在新的goroutine中执行的代码 }() // main goroutine会继续执行 }

channels

channel是在并发编程中用于多个goroutine之间通信的机制。它可以使goroutine之间通过发送和接收值进行同步。在Go语言中,使用make函数创建一个channel。

goCopy Code
ch := make(chan int)

发送和接收值

通过channel发送和接收值的语法都很简单。要发送一个值到channel中,可以使用<-操作符。

goCopy Code
ch <- value

要从channel中接收一个值,可以使用<-操作符将其赋值给变量。

goCopy Code
value := <-ch

阻塞和非阻塞操作

channel操作可以是阻塞的或非阻塞的。当尝试向一个已满的channel发送数据或从一个空channel接收数据时,操作将被阻塞。非阻塞操作可以在无法完成操作时立即返回。

goCopy Code
// 阻塞发送 ch <- value // 阻塞接收 value := <-ch // 非阻塞发送 select { case ch <- value: fmt.Println("Sent value to channel") default: fmt.Println("Channel is full") } // 非阻塞接收 select { case value := <-ch: fmt.Println("Received value from channel") default: fmt.Println("Channel is empty") }

实例

下面是一个使用goroutines和channels实现并发下载的例子。它会同时下载多个URL,并将结果发送到管道中。

goCopy Code
func main() { urls := []string{"https://www.google.com", "https://www.youtube.com", "https://www.bing.com"} ch := make(chan string) for _, url := range urls { go func(url string) { resp, err := http.Get(url) if err != nil { ch <- fmt.Sprintf("Error fetching %s: %s", url, err) return } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { ch <- fmt.Sprintf("Error reading body from %s: %s", url, err) return } ch <- fmt.Sprintf("%s\n%s", url, body) }(url) } for range urls { fmt.Println(<-ch) } }