func CalSquare() {
src := make(chan int)
dest := make(chan int, 3)
go func() {
defer close(src)
for i := 0; i < 10; i++ {
src <- i
}
}()
go func() {
defer close(dest)
for i := range src {
dest <- i * i
}
}()
for i := range dest {
println(i)
}
-
包声明:
go package concurrence 这一行声明了代码所在的包为
concurrence。 -
函数定义:
go
func CalSquare() {
//...
}
这是一个名为
CalSquare的函数,它没有参数也没有返回值。 -
创建通道:
go src := make(chan int) dest := make(chan int, 3) 这里创建了两个通道:
src和dest。src是一个无缓冲通道,用于发送整数;dest是一个有缓冲通道,容量为3,用于接收平方数。 -
启动生成器协程: go go func() { defer close(src) for i := 0; i < 10; i++ { src <- i } }()
这个匿名函数创建了一个协程,它向
src通道发送从0到9的整数,然后关闭src通道。 -
启动计算协程:
go go func() { defer close(dest) for i := range src { dest <- i * i } }() 这个匿名函数也创建了一个协程,它从
src通道接收整数,计算平方,并将结果发送到dest通道,然后关闭dest通道。 -
主协程接收并打印结果:
go for i := range dest { println(i) }
主协程从
dest通道接收平方数,并打印出来。
总结来说,这个程序通过两个协程并发地生成整数和计算平方,然后在主协程中打印结果。这种并发模型允许程序高效地处理多个任务,提高了程序的性能和响应速度。
Go 语言的并发模型基于 goroutines 和 channels,这是一种非常高效且易于使用的并发方式。下面将补充一些 Go 并发的进阶概念和技巧:
- Goroutines: Goroutine 是 Go 语言中的轻量级线程,由 Go 运行时管理。它们非常便宜,可以轻松创建成千上万个。Goroutines 通过
go关键字启动。 - Channels: Channels 是 Go 语言中用于在 goroutines 之间安全传递数据的管道。它们可以是无缓冲的或有缓冲的。无缓冲的 channels 同步发送和接收操作,而有缓冲的 channels 允许一定数量的值在没有接收者的情况下发送。
- Select 语句:
select语句用于同时等待多个 channels 的操作。这在你需要从多个 channels 中接收数据或者向多个 channels 发送数据时非常有用。 - Default Case in Select: 在
select语句中,如果没有其他 case 可以运行,可以选择执行一个默认 case。 - sync 包: Go 标准库中的
sync包提供了互斥锁(Mutex)、读写锁(RWMutex)和条件变量(Cond),用于更细粒度的同步控制。 - WaitGroup:
sync.WaitGroup用于等待一组 goroutines 完成。它通过Add方法增加计数器,每个 goroutine 完成时调用Done方法减少计数器,主 goroutine 通过Wait方法等待计数器归零。 - Once:
sync.Once用于确保初始化或其他互斥执行的代码块只被执行一次。 - 原子操作: Go 语言提供了原子操作,如
atomic.AddInt32,这些操作不需要使用互斥锁就可以安全地在多个 goroutines 之间共享变量。 - Error Handling: 在并发编程中,错误处理非常重要。通常,你会通过返回值来传递错误,或者使用 channels 来传递错误信息。
- Context:
context包用于在 goroutines 之间传递状态信息,如取消信号或截止时间。这对于编写可取消的并发操作非常有用。 - Rate Limiting: 通过使用
golang.org/x/time/rate包,你可以实现对 goroutines 的速率限制,这对于控制资源使用或防止过载非常有用。 - Select with Timeout: 你可以在
select语句中使用time.After函数来实现超时逻辑。