数据结构和算法-Go泛型实现:第一章并发与泛型基础-1. 并发编程

93 阅读3分钟

第一章:并发与泛型基础

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 来实现并发编程。