第一章:并发与泛型基础
1. 并发编程
Goroutine
Goroutine 是 Go 语言中的轻量级线程管理。在 Go 语言中,你可以使用 go 关键字来启动一个新的 Goroutine。例如:
go func() {
fmt.Println("Hello from a goroutine!")
}()
这个 Goroutine 将并发执行,而无需等待它完成。
WaitGroup
sync.WaitGroup 提供了一种等待一组 Goroutine 完成的方法。可以通过添加计数、减少计数以及等待所有计数变为零来同步 Goroutine。
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
fmt.Println("Goroutine is done")
}()
wg.Wait()
这段代码将等待 Goroutine 完成后才继续执行。
Channel
Channel 是 Go 语言中用于 Goroutine 之间通信的管道。可以通过 make 函数创建 Channel,并使用 <- 运算符发送和接收数据。
ch := make(chan int)
go func() {
ch <- 42
}()
value := <-ch
fmt.Println(value)
这段代码演示了如何在 Goroutine 之间传递数据。
Select 语句
select 语句用于在多个 Channel 操作中进行选择。如果多个 Channel 同时准备好,select 将随机选择一个执行。
select {
case msg1 := <-ch1:
fmt.Println("Received", msg1)
case msg2 := <-ch2:
fmt.Println("Received", msg2)
default:
fmt.Println("No message received")
}
这段代码展示了如何使用 select 从多个 Channel 接收数据。
使用 quit Channel 代替 WaitGroup
通过使用一个 quit Channel,可以避免使用 WaitGroup 来等待 Goroutine 完成。
quit := make(chan bool)
go func() {
defer close(quit)
fmt.Println("Goroutine is done")
}()
<-quit
这段代码展示了如何使用 quit Channel 等待 Goroutine 完成。
Channel 方向
Channel 可以有发送或接收方向,用于限制函数中 Channel 的使用方式。
func sendData(ch chan<- int) {
ch <- 42
}
func receiveData(ch <-chan int) {
value := <-ch
fmt.Println(value)
}
这段代码定义了只发送数据和只接收数据的 Channel。
竞争条件
竞争条件发生在多个 Goroutine 访问共享资源且至少一个访问是写操作时。可以使用 go run -race 命令来检测竞争条件。
互斥锁
sync.Mutex 提供了一种确保在同一时间只有一个 Goroutine 访问共享资源的方法。
var mu sync.Mutex
mu.Lock()
// 访问共享资源
mu.Unlock()
这段代码展示了如何使用互斥锁保护共享资源。
使用 Goroutine 实现国际象棋
通过使用 Goroutine,可以并发地计算国际象棋的下一步。
type Move struct {
from, to string
}
moves := make(chan Move)
quit := make(chan bool)
go func() {
for {
select {
case move := <-moves:
fmt.Println("Move from", move.from, "to", move.to)
case <-quit:
return
}
}
}()
moves <- Move{"e2", "e4"}
quit <- true
这段代码展示了如何使用 Goroutine 和 Channel 实现一个简单的国际象棋移动计算。
使用 Goroutine 计算斐波那契数列
使用 Goroutine 并发地计算斐波那契数列。
func fibonacci(n int, c chan int) {
x, y := 0, 1
for i := 0; i < n; i++ {
c <- x
x, y = y, x+y
}
close(c)
}
c := make(chan int, 10)
go fibonacci(cap(c), c)
for i := range c {
fmt.Println(i)
}
这段代码展示了如何使用 Goroutine 并发地计算并打印斐波那契数列。
第一章内容涉及并发编程的基础概念和实际应用。通过这些示例,读者可以学习如何在 Go 语言中使用 Goroutine 和 Channel 来实现并发编程。