Go 语言并发编程介绍
Go 语言设计时就考虑了并发编程的需求,提供了轻量级的线程(goroutine)和通道(channel)作为并发编程的基础。以下是 Go 语言并发编程的一些关键概念和特性:
- Goroutine
定义:Goroutine 是 Go 语言中的轻量级线程,由 Go 运行时管理。
创建:使用 go 关键字启动一个新的 Goroutine。
示例:
package main
import (
"fmt"
"time"
)
func say(s string) {
for i := 0; i < 5; i++ {
time.Sleep(100 * time.Millisecond)
fmt.Println(s)
}
}
func main() {
go say("world")
say("hello")
}
- Channel
定义:Channel 是 Goroutine 之间通信的管道,用于在不同的 Goroutine 之间传递数据。
创建:使用 make 函数创建 Channel。
类型:Channel 可以是单向的(只能发送或接收)或双向的(可以发送和接收)。
示例:
import (
"fmt"
)
func sum(s []int, c chan int) {
sum := 0
for _, v := range s {
sum += v
}
c <- sum // 将结果发送到 Channel
}
func main() {
s := []int{7, 2, 8, -9, 4, 0}
c := make(chan int)
go sum(s[:len(s)/2], c)
go sum(s[len(s)/2:], c)
x, y := <-c, <-c // 从 Channel 接收结果
fmt.Println(x, y, x+y)
}
- 同步原语
WaitGroup:用于等待多个 Goroutine 完成。
Mutex:用于保护共享资源的互斥锁。
示例:
package main
import (
"fmt"
"sync"
)
func main() {
var wg sync.WaitGroup
var mu sync.Mutex
var counter int
for i := 0; i < 1000; i++ {
wg.Add(1)
go func() {
defer wg.Done()
mu.Lock()
counter++
mu.Unlock()
}()
}
wg.Wait()
fmt.Println("Counter:", counter)
}
- 选择语句(Select)
定义:select 语句用于在多个 Channel 操作之间进行选择。
示例:
package main
import (
"fmt"
"time"
)
func main() {
c1 := make(chan string)
c2 := make(chan string)
go func() {
time.Sleep(1 * time.Second)
c1 <- "one"
}()
go func() {
time.Sleep(2 * time.Second)
c2 <- "two"
}()
for i := 0; i < 2; i++ {
select {
case msg1 := <-c1:
fmt.Println("Received:", msg1)
case msg2 := <-c2:
fmt.Println("Received:", msg2)
}
}
}
- 上下文(Context)
定义:Context 用于在 Goroutine 之间传递请求范围的值、取消信号等。
示例:
package main
import (
"context"
"fmt"
"time"
)
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
defer cancel()
done := make(chan bool, 1)
go func(ctx context.Context) {
select {
case <-ctx.Done():
fmt.Println("Context canceled:", ctx.Err())
done <- true
case <-time.After(2 * time.Second):
fmt.Println("Task completed")
done <- true
}
}(ctx)
<-done
}