Add Chapter 5: Concurrency - Goroutines, Channels, Sync Primitives, and Patterns (Deep Dive)

This commit is contained in:
openclaw
2026-03-23 23:36:39 +00:00
parent aa46d006a8
commit f79acea8a8
3 changed files with 1140 additions and 0 deletions

View File

@@ -0,0 +1,3 @@
module go-tutorial
go 1.21

371
chapters/chapter-5/main.go Normal file
View File

@@ -0,0 +1,371 @@
package main
import (
"context"
"fmt"
"sync"
"sync/atomic"
"time"
)
// 5.1 Goroutine 基础
func say(s string) {
for i := 0; i < 3; i++ {
time.Sleep(100 * time.Millisecond)
fmt.Println(s)
}
}
func goroutineBasic() {
fmt.Println("=== Goroutine 基础 ===")
go say("world")
say("hello")
time.Sleep(500 * time.Millisecond)
}
// 5.2 GMP 模型演示
func gmpDemo() {
fmt.Println("\n=== GMP 模型 ===")
fmt.Printf("GOMAXPROCS: %d\n", runtime.GOMAXPROCS(0))
fmt.Printf("NumCPU: %d\n", runtime.NumCPU())
fmt.Printf("NumGoroutine: %d\n", runtime.NumGoroutine())
}
// 5.3 Channel 基础
func channelBasic() {
fmt.Println("\n=== Channel 基础 ===")
// 无缓冲 Channel
ch := make(chan int)
go func() {
ch <- 42
}()
val := <-ch
fmt.Println("无缓冲 Channel:", val)
// 有缓冲 Channel
bufferedCh := make(chan int, 2)
bufferedCh <- 1
bufferedCh <- 2
fmt.Println("有缓冲 Channel:", <-bufferedCh, <-bufferedCh)
}
// 5.3 Channel 关闭与遍历
func channelClose() {
fmt.Println("\n=== Channel 关闭与遍历 ===")
ch := make(chan int)
go func() {
for i := 0; i < 5; i++ {
ch <- i
}
close(ch)
}()
for val := range ch {
fmt.Print(val, " ")
}
fmt.Println()
// 检查关闭
if _, ok := <-ch; !ok {
fmt.Println("Channel 已关闭")
}
}
// 5.3 工作池
func worker(id int, jobs <-chan int, results chan<- int) {
for j := range jobs {
fmt.Printf("Worker %d 处理 %d\n", id, j)
time.Sleep(100 * time.Millisecond)
results <- j * 2
}
}
func workerPoolDemo() {
fmt.Println("\n=== 工作池 ===")
jobs := make(chan int, 10)
results := make(chan int, 10)
for w := 1; w <= 3; w++ {
go worker(w, jobs, results)
}
for j := 1; j <= 5; j++ {
jobs <- j
}
close(jobs)
for r := 1; r <= 5; r++ {
<-results
}
fmt.Println("工作池完成")
}
// 5.3 Select
func selectDemo() {
fmt.Println("\n=== Select ===")
ch1 := make(chan string)
ch2 := make(chan string)
go func() {
time.Sleep(500 * time.Millisecond)
ch1 <- "来自 ch1"
}()
go func() {
time.Sleep(300 * time.Millisecond)
ch2 <- "来自 ch2"
}()
for i := 0; i < 2; i++ {
select {
case msg1 := <-ch1:
fmt.Println(msg1)
case msg2 := <-ch2:
fmt.Println(msg2)
case <-time.After(1 * time.Second):
fmt.Println("超时")
return
}
}
}
// 5.4 WaitGroup
func waitGroupDemo() {
fmt.Println("\n=== WaitGroup ===")
var wg sync.WaitGroup
for i := 0; i < 5; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
fmt.Printf("Worker %d 开始\n", id)
time.Sleep(200 * time.Millisecond)
fmt.Printf("Worker %d 完成\n", id)
}(i)
}
wg.Wait()
fmt.Println("所有任务完成")
}
// 5.4 Mutex
func mutexDemo() {
fmt.Println("\n=== Mutex ===")
var mu sync.Mutex
var count int
for i := 0; i < 1000; i++ {
go func() {
mu.Lock()
count++
mu.Unlock()
}()
}
time.Sleep(1 * time.Second)
fmt.Println("Count:", count)
}
// 5.4 RWMutex
func rwMutexDemo() {
fmt.Println("\n=== RWMutex ===")
var mu sync.RWMutex
var data = make(map[string]int)
var wg sync.WaitGroup
// 读操作
for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
defer wg.Done()
mu.RLock()
_ = data["key"]
mu.RUnlock()
}()
}
// 写操作
for i := 0; i < 5; i++ {
wg.Add(1)
go func() {
defer wg.Done()
mu.Lock()
data["key"]++
mu.Unlock()
}()
}
wg.Wait()
fmt.Println("Data:", data)
}
// 5.4 Once
func onceDemo() {
fmt.Println("\n=== Once ===")
var once sync.Once
setup := func() {
fmt.Println("初始化一次")
}
for i := 0; i < 5; i++ {
go func() {
once.Do(setup)
}()
}
time.Sleep(500 * time.Millisecond)
}
// 5.5 Atomic
func atomicDemo() {
fmt.Println("\n=== Atomic ===")
var count int64
for i := 0; i < 1000; i++ {
go func() {
atomic.AddInt64(&count, 1)
}()
}
time.Sleep(1 * time.Second)
fmt.Println("Atomic Count:", atomic.LoadInt64(&count))
}
// 5.6 Context
func contextDemo() {
fmt.Println("\n=== Context ===")
ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond)
defer cancel()
go func() {
select {
case <-time.After(1 * time.Second):
fmt.Println("任务完成")
case <-ctx.Done():
fmt.Println("任务取消:", ctx.Err())
}
}()
time.Sleep(1 * time.Second)
}
// 5.8 管道
func pipelineDemo() {
fmt.Println("\n=== 管道 ===")
// 生成
gen := func(nums ...int) <-chan int {
out := make(chan int)
go func() {
for _, n := range nums {
out <- n
}
close(out)
}()
return out
}
// 平方
sq := func(in <-chan int) <-chan int {
out := make(chan int)
go func() {
for n := range in {
out <- n * n
}
close(out)
}()
return out
}
c := gen(1, 2, 3)
c = sq(c)
for n := range c {
fmt.Println(n)
}
}
// 5.9 并发爬虫
type Crawler struct {
visited map[string]bool
mu sync.Mutex
wg sync.WaitGroup
limit chan struct{}
}
func (c *Crawler) crawl(url string, depth int) {
if depth <= 0 {
return
}
c.limit <- struct{}{}
defer func() { <-c.limit }()
defer c.wg.Done()
c.mu.Lock()
if c.visited[url] {
c.mu.Unlock()
return
}
c.visited[url] = true
c.mu.Unlock()
fmt.Println("抓取:", url)
// 模拟子链接
links := []string{url + "/1", url + "/2"}
for _, link := range links {
c.wg.Add(1)
go c.crawl(link, depth-1)
}
}
func crawlerDemo() {
fmt.Println("\n=== 并发爬虫 ===")
crawler := &Crawler{
visited: make(map[string]bool),
limit: make(chan struct{}, 5),
}
crawler.wg.Add(1)
go crawler.crawl("http://example.com", 2)
crawler.wg.Wait()
fmt.Println("爬虫完成")
}
// 5.10 竞态检测示例(需配合 -race 运行)
func raceDemo() {
fmt.Println("\n=== 竞态检测示例 ===")
var count int
for i := 0; i < 100; i++ {
go func() {
count++ // 竞态!
}()
}
time.Sleep(1 * time.Second)
fmt.Println("Count:", count)
}
func main() {
goroutineBasic()
gmpDemo()
channelBasic()
channelClose()
workerPoolDemo()
selectDemo()
waitGroupDemo()
mutexDemo()
rwMutexDemo()
onceDemo()
atomicDemo()
contextDemo()
pipelineDemo()
crawlerDemo()
raceDemo()
}