Go语言使用goroutine及通道实现并发详解
前言
在进行并发编程时,一个优雅而简单的方式是使用goroutine和通道(channel)进行操作。本文将详细讲解使用Go语言实现并发的方法,通过学习本文内容,读者将掌握以下知识点:
- goroutine使用方法
- 通道(channel)与缓冲区使用方法
- select语句的使用
goroutine使用方法
goroutine是Go语言中的一个并发执行的单元,类似于线程。但是goroutine的开销比线程小得多,一个程序中可以同时启动成千上万的goroutine。
下面是一个简单的goroutine的实现代码:
func PrintGo() {
fmt.Print("Goroutine.")
}
func main() {
go PrintGo() // 启动一个goroutine
fmt.Print("Hello, ")
}
在上述代码中,通过在PrintGo函数前加上一个go
关键字,就可以启用一个goroutine。在main
函数中,调用PrintGo
函数如同调用普通函数,但是PrintGo
函数的执行却是在另外一个goroutine中,与main
函数是异步执行的。
需要注意的是,当main
函数完成执行时,所有的goroutine都会被强制停止。如果需要让goroutine一直执行,需要加入阻塞代码或类似于time.Sleep()
的代码。
func PrintGo() {
for {
fmt.Print("Go. ")
time.Sleep(time.Millisecond * 500)
}
}
func main() {
go PrintGo() // 启动一个goroutine
fmt.Print("Hello, ")
time.Sleep(time.Second * 3)
}
上述代码中,由于在PrintGo
函数中加入了一个无限循环和阻塞代码(time.Sleep()
),goroutine一直在执行。
通道(channel)与缓冲区使用方法
通道是一种允许在goroutine间进行数据传递的方式,类似于在管道中传递数据的方式。通道是Go语言中的一个重要特性,通过通道可以使不同的goroutine之间保持并发执行,增强程序的效率。
下面是一个简单的通道的实现代码:
func SendData(data string, ch chan string) {
ch <- data // 将data写入到管道中
}
func main() {
ch := make(chan string) // 创建管道
go SendData("Hi, I'm data.", ch) // 启动一个goroutine将数据写入到管道中
recData := <-ch // 从管道中读取数据
fmt.Print(recData)
}
以上代码中,创建了一个名为ch
的通道。SendData
函数是一个goroutine,负责将数据写入到ch
中,而main
函数中则通过<-ch
从通道中读取数据。
由于通道在进行数据读写时是同步的,因此若在没有接收方时,发送方写入数据,将导致程序阻塞而无法继续执行。为解决这个问题,Go语言中引入了缓冲通道。
通过在创建通道时的参数设置缓存大小,就可以创建一个缓存通道。当发送方写入的数据不超过缓存长度时,程序不会阻塞。
下面是一个实现缓存通道的示例代码:
func SendData(data string, ch chan string) {
ch <- data // 将data写入到缓存通道中
fmt.Print("Cache channel is not block.")
}
func main() {
ch := make(chan string, 1) // 创建一个缓存大小为1的缓存通道
go SendData("Hi, I'm data.", ch) // 启动一个goroutine将数据写入到管道中
recData := <-ch // 从管道中读取数据
fmt.Print(recData)
}
以上代码中,创建了一个大小为1的缓存通道,当go SendData("Hi, I'm data.", ch)
这行代码执行时,由于缓存通道大小为1,所以不会阻塞,fmt.Print("Cache channel is not block.")
会被执行;当recData := <-ch
行被执行时,因为SendData
已经完成对缓存通道的写入,<-ch
即可被接收到数据。
select语句的使用
select是Go语言中用来处理通道操作的语句,它可以同时监控多个通道,当其中的任意一个通道满足条件时,就会执行相应的分支。这使得处理多个通道操作变得容易。
下面是一个使用select语句的示例:
func SendData(data string, ch1 chan string, ch2 chan string) {
select {
case ch1 <- data: // 向通道ch1写入数据
fmt.Print("Data is sended by channel 1.")
case ch2 <- data: // 向通道ch2写入数据
fmt.Print("Data is sended by channel 2.")
}
}
func main() {
ch1 := make(chan string)
ch2 := make(chan string)
go SendData("Hi, I'm data.", ch1, ch2) // 启动一个goroutine将数据写入到通道中
time.Sleep(time.Second)
}
以上代码中,定义了两个通道ch1
和ch2
,SendData
函数负责向两个通道中写入数据,并且使用了select语句来监控通道操作。当两个通道都可写时,select
语句会随机执行。
小结
本文详细讲解了使用Go语言实现并发的方法,包括goroutine、通道和缓存、select语句等。并给出了多条示例代码来帮助读者更好地理解这些知识点。希望本文能对您有所帮助。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Go语言使用goroutine及通道实现并发详解 - Python技术站