Go 并发学习笔记
什么是Go并发?
Go并发是指在同一时间内执行多个线程或任务的能力。Go语言使用goroutines和channels机制来实现并发。
goroutines
goroutine是轻量级的线程,由Go运行时管理。与线程相比,它们拥有更小的堆栈大小(一般为2KB)并且更加高效。在Go程序中启动一个goroutine非常简单,只需要在函数调用前加上关键字go即可。
goCopy Codefunc main() {
go func() {
// 在新的goroutine中执行的代码
}()
// main goroutine会继续执行
}
channels
channel是在并发编程中用于多个goroutine之间通信的机制。它可以使goroutine之间通过发送和接收值进行同步。在Go语言中,使用make函数创建一个channel。
goCopy Codech := make(chan int)
发送和接收值
通过channel发送和接收值的语法都很简单。要发送一个值到channel中,可以使用<-操作符。
goCopy Codech <- value
要从channel中接收一个值,可以使用<-操作符将其赋值给变量。
goCopy Codevalue := <-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 Codefunc 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)
}
}