Java转Go全过程03-并发编程部分

6 阅读13分钟

Java开发已经是红海一片,面临着35岁危机的压力,需要适时的调整策略,以应对可能会出现的不确定性。毕竟,命运掌握在自己手里,比掌握在公司手里 安全感会强很多。

尝试的其中一条路即为:Java转Go,海外开发web3相关,也有其他的尝试,会开辟相应的专栏收录。

针对每一个部分,都会在最后准备练习题,可以多做几遍,用于巩固知识,多动手!

后续golang语言学习过程中产生的全部内容,会发布在 web3这个专栏中。

Go语言基础快速突破[并发编程](1-2周)

1. 并发基础

并发编程是Go语言的核心特性之一。与Java的线程模型不同,Go使用goroutine实现轻量级并发。

核心概念:

  • 并发 vs 并行:并发是同时处理多个任务的能力,并行是同时执行多个任务
  • CSP模型:Communicating Sequential Processes,通过通信来共享内存,而不是通过共享内存来通信
// 并发基础示例
package main

import (
    "fmt"
    "time"
)

func main() {
    // 顺序执行
    fmt.Println("顺序执行开始")
    task1()
    task2()
    fmt.Println("顺序执行结束")
    
    // 并发执行
    fmt.Println("并发执行开始")
    go task1()
    go task2()
    time.Sleep(2 * time.Second) // 等待goroutine完成
    fmt.Println("并发执行结束")
}

func task1() {
    for i := 0; i < 3; i++ {
        fmt.Printf("Task1: %d\n", i)
        time.Sleep(100 * time.Millisecond)
    }
}

func task2() {
    for i := 0; i < 3; i++ {
        fmt.Printf("Task2: %d\n", i)
        time.Sleep(150 * time.Millisecond)
    }
}

2. 协程

协程(Coroutine)是Go语言中的轻量级线程,由Go运行时管理。

特点:

  • 启动成本低(2KB栈空间)
  • 可以轻松创建数万个协程
  • 由Go运行时调度,非操作系统线程
package main

import (
    "fmt"
    "runtime"
    "time"
)

func main() {
    fmt.Printf("当前GOMAXPROCS: %d\n", runtime.GOMAXPROCS(0))
    
    // 创建多个协程
    for i := 0; i < 5; i++ {
        go func(id int) {
            fmt.Printf("协程 %d 开始执行\n", id)
            time.Sleep(time.Duration(id) * 100 * time.Millisecond)
            fmt.Printf("协程 %d 执行完成\n", id)
        }(i)
    }
    
    time.Sleep(1 * time.Second)
    fmt.Printf("当前活跃协程数: %d\n", runtime.NumGoroutine())
}

3. goroutine

goroutine是Go语言中并发的基本单位,使用go关键字启动。

语法:

go functionName()           // 启动无参数函数
go func() { ... }()         // 启动匿名函数
go func(params) { ... }(args) // 启动带参数的匿名函数
package main

import (
    "fmt"
    "sync"
    "time"
)

func main() {
    var wg sync.WaitGroup
    
    // 使用WaitGroup等待所有goroutine完成
    for i := 0; i < 3; i++ {
        wg.Add(1)
        go func(id int) {
            defer wg.Done()
            fmt.Printf("Goroutine %d 开始\n", id)
            time.Sleep(time.Duration(id+1) * 200 * time.Millisecond)
            fmt.Printf("Goroutine %d 结束\n", id)
        }(i)
    }
    
    wg.Wait()
    fmt.Println("所有goroutine完成")
}

4. 并发通信

Go语言推荐通过通信来共享内存,而不是通过共享内存来通信。

通信方式:

  • Channel(通道)
  • 共享内存(sync包)
package main

import (
    "fmt"
    "time"
)

func main() {
    // 使用channel进行通信
    ch := make(chan string)
    
    go sender(ch)
    go receiver(ch)
    
    time.Sleep(2 * time.Second)
}

func sender(ch chan string) {
    messages := []string{"Hello", "World", "Go", "Concurrency"}
    for _, msg := range messages {
        ch <- msg
        time.Sleep(100 * time.Millisecond)
    }
    close(ch) // 发送完成后关闭channel
}

func receiver(ch chan string) {
    for msg := range ch {
        fmt.Printf("收到消息: %s\n", msg)
    }
    fmt.Println("接收完成")
}

5. channel

Channel是Go语言中goroutine之间通信的主要方式。

5.1 基本语法

package main

import (
    "fmt"
    "time"
)

func main() {
    // 创建channel
    ch := make(chan int)
    
    // 发送数据
    go func() {
        for i := 0; i < 5; i++ {
            ch <- i
            time.Sleep(100 * time.Millisecond)
        }
        close(ch)
    }()
    
    // 接收数据
    for num := range ch {
        fmt.Printf("接收到: %d\n", num)
    }
}

5.2 select

select语句用于在多个channel操作中进行选择。

package main

import (
    "fmt"
    "time"
)

func main() {
    ch1 := make(chan string)
    ch2 := make(chan string)
    
    go func() {
        time.Sleep(1 * time.Second)
        ch1 <- "来自ch1的消息"
    }()
    
    go func() {
        time.Sleep(2 * time.Second)
        ch2 <- "来自ch2的消息"
    }()
    
    for i := 0; i < 2; i++ {
        select {
        case msg1 := <-ch1:
            fmt.Println(msg1)
        case msg2 := <-ch2:
            fmt.Println(msg2)
        case <-time.After(3 * time.Second):
            fmt.Println("超时")
            return
        }
    }
}

5.3 缓冲机制

带缓冲的channel可以在发送方不阻塞的情况下存储多个值。

package main

import (
    "fmt"
    "time"
)

func main() {
    // 创建带缓冲的channel,容量为3
    ch := make(chan int, 3)
    
    // 发送数据(不会阻塞,因为缓冲区有空间)
    go func() {
        for i := 0; i < 5; i++ {
            ch <- i
            fmt.Printf("发送: %d\n", i)
            time.Sleep(100 * time.Millisecond)
        }
        close(ch)
    }()
    
    // 接收数据
    for num := range ch {
        fmt.Printf("接收: %d\n", num)
        time.Sleep(200 * time.Millisecond)
    }
}

5.4 超时机制

使用select和time.After实现超时机制。

package main

import (
    "fmt"
    "time"
)

func main() {
    ch := make(chan string)
    
    go func() {
        time.Sleep(3 * time.Second)
        ch <- "完成"
    }()
    
    select {
    case result := <-ch:
        fmt.Printf("成功: %s\n", result)
    case <-time.After(2 * time.Second):
        fmt.Println("操作超时")
    }
}

5.5 channel的传递

Channel可以作为参数传递给函数。

package main

import (
    "fmt"
    "time"
)

func main() {
    ch := make(chan int)
    
    go producer(ch)
    go consumer(ch)
    
    time.Sleep(2 * time.Second)
}

func producer(ch chan int) {
    for i := 0; i < 5; i++ {
        ch <- i
        time.Sleep(100 * time.Millisecond)
    }
    close(ch)
}

func consumer(ch chan int) {
    for num := range ch {
        fmt.Printf("消费: %d\n", num)
    }
}

5.6 单向channel

可以限制channel的读写权限。

package main

import (
    "fmt"
    "time"
)

func main() {
    ch := make(chan int)
    
    // 传递只写channel给producer
    go producer(ch)
    // 传递只读channel给consumer
    go consumer(ch)
    
    time.Sleep(2 * time.Second)
}

// 只写channel
func producer(ch chan<- int) {
    for i := 0; i < 5; i++ {
        ch <- i
        time.Sleep(100 * time.Millisecond)
    }
    close(ch)
}

// 只读channel
func consumer(ch <-chan int) {
    for num := range ch {
        fmt.Printf("消费: %d\n", num)
    }
}

5.7 关闭channel

关闭channel后,接收方会立即收到零值。

package main

import (
    "fmt"
    "time"
)

func main() {
    ch := make(chan int)
    
    go func() {
        for i := 0; i < 3; i++ {
            ch <- i
            time.Sleep(100 * time.Millisecond)
        }
        close(ch) // 关闭channel
    }()
    
    // 检查channel是否关闭
    for {
        value, ok := <-ch
        if !ok {
            fmt.Println("Channel已关闭")
            break
        }
        fmt.Printf("接收到: %d\n", value)
    }
}

6. 多核并行化

利用多核CPU进行并行计算。

package main

import (
    "fmt"
    "runtime"
    "sync"
    "time"
)

func main() {
    fmt.Printf("CPU核心数: %d\n", runtime.NumCPU())
    
    // 设置使用所有CPU核心
    runtime.GOMAXPROCS(runtime.NumCPU())
    
    start := time.Now()
    
    // 串行计算
    result1 := serialSum(10000000)
    fmt.Printf("串行结果: %d, 耗时: %v\n", result1, time.Since(start))
    
    start = time.Now()
    // 并行计算
    result2 := parallelSum(10000000)
    fmt.Printf("并行结果: %d, 耗时: %v\n", result2, time.Since(start))
}

func serialSum(n int) int {
    sum := 0
    for i := 0; i < n; i++ {
        sum += i
    }
    return sum
}

func parallelSum(n int) int {
    numCPU := runtime.NumCPU()
    chunkSize := n / numCPU
    
    var wg sync.WaitGroup
    results := make(chan int, numCPU)
    
    for i := 0; i < numCPU; i++ {
        wg.Add(1)
        start := i * chunkSize
        end := start + chunkSize
        if i == numCPU-1 {
            end = n
        }
        
        go func(start, end int) {
            defer wg.Done()
            sum := 0
            for j := start; j < end; j++ {
                sum += j
            }
            results <- sum
        }(start, end)
    }
    
    wg.Wait()
    close(results)
    
    total := 0
    for sum := range results {
        total += sum
    }
    
    return total
}

7. 出让时间片

使用runtime.Gosched()让出CPU时间片。

package main

import (
    "fmt"
    "runtime"
    "time"
)

func main() {
    go greedyTask()
    go normalTask()
    
    time.Sleep(2 * time.Second)
}

func greedyTask() {
    for i := 0; i < 5; i++ {
        fmt.Printf("贪婪任务 %d\n", i)
        // 不让出时间片,占用CPU
        for j := 0; j < 1000000; j++ {
            // 空循环
        }
    }
}

func normalTask() {
    for i := 0; i < 5; i++ {
        fmt.Printf("正常任务 %d\n", i)
        runtime.Gosched() // 让出时间片
        time.Sleep(100 * time.Millisecond)
    }
}

8. 同步

8.1 同步锁

使用sync.Mutex进行互斥锁同步。

package main

import (
    "fmt"
    "sync"
    "time"
)

type Counter struct {
    mu    sync.Mutex
    count int
}

func (c *Counter) Increment() {
    c.mu.Lock()
    defer c.mu.Unlock()
    c.count++
}

func (c *Counter) GetCount() int {
    c.mu.Lock()
    defer c.mu.Unlock()
    return c.count
}

func main() {
    counter := &Counter{}
    var wg sync.WaitGroup
    
    // 启动多个goroutine同时增加计数
    for i := 0; i < 10; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            for j := 0; j < 1000; j++ {
                counter.Increment()
            }
        }()
    }
    
    wg.Wait()
    fmt.Printf("最终计数: %d\n", counter.GetCount())
}

8.2 全局唯一性操作

使用sync.Once确保某个操作只执行一次。

package main

import (
    "fmt"
    "sync"
    "time"
)

type Singleton struct {
    data string
}

var (
    instance *Singleton
    once     sync.Once
)

func GetInstance() *Singleton {
    once.Do(func() {
        instance = &Singleton{data: "初始化数据"}
        fmt.Println("单例已初始化")
    })
    return instance
}

func main() {
    var wg sync.WaitGroup
    
    // 多个goroutine同时获取单例
    for i := 0; i < 5; i++ {
        wg.Add(1)
        go func(id int) {
            defer wg.Done()
            singleton := GetInstance()
            fmt.Printf("Goroutine %d 获取到单例: %s\n", id, singleton.data)
        }(i)
    }
    
    wg.Wait()
}

9. 完整示例

9.1 简单IPC框架

// ipc.go
package main

import (
    "encoding/json"
    "fmt"
    "sync"
)

type Message struct {
    Type    string      `json:"type"`
    Content interface{} `json:"content"`
    ID      int         `json:"id"`
}

type IPC struct {
    handlers map[string]func(Message) Message
    mu       sync.RWMutex
}

func NewIPC() *IPC {
    return &IPC{
        handlers: make(map[string]func(Message) Message),
    }
}

func (ipc *IPC) RegisterHandler(msgType string, handler func(Message) Message) {
    ipc.mu.Lock()
    defer ipc.mu.Unlock()
    ipc.handlers[msgType] = handler
}

func (ipc *IPC) HandleMessage(msg Message) Message {
    ipc.mu.RLock()
    handler, exists := ipc.handlers[msg.Type]
    ipc.mu.RUnlock()
    
    if !exists {
        return Message{
            Type:    "error",
            Content: "未知消息类型",
            ID:      msg.ID,
        }
    }
    
    return handler(msg)
}

9.2 中央服务器

// server.go
package main

import (
    "fmt"
    "sync"
    "time"
)

type Server struct {
    ipc      *IPC
    clients  map[int]chan Message
    mu       sync.RWMutex
    nextID   int
}

func NewServer() *Server {
    server := &Server{
        ipc:     NewIPC(),
        clients: make(map[int]chan Message),
    }
    
    // 注册消息处理器
    server.ipc.RegisterHandler("echo", server.handleEcho)
    server.ipc.RegisterHandler("broadcast", server.handleBroadcast)
    
    return server
}

func (s *Server) RegisterClient() int {
    s.mu.Lock()
    defer s.mu.Unlock()
    
    id := s.nextID
    s.nextID++
    s.clients[id] = make(chan Message, 10)
    
    fmt.Printf("客户端 %d 已注册\n", id)
    return id
}

func (s *Server) UnregisterClient(id int) {
    s.mu.Lock()
    defer s.mu.Unlock()
    
    if ch, exists := s.clients[id]; exists {
        close(ch)
        delete(s.clients, id)
        fmt.Printf("客户端 %d 已注销\n", id)
    }
}

func (s *Server) SendMessage(clientID int, msg Message) {
    s.mu.RLock()
    ch, exists := s.clients[clientID]
    s.mu.RUnlock()
    
    if exists {
        ch <- msg
    }
}

func (s *Server) handleEcho(msg Message) Message {
    return Message{
        Type:    "echo_response",
        Content: msg.Content,
        ID:      msg.ID,
    }
}

func (s *Server) handleBroadcast(msg Message) Message {
    s.mu.RLock()
    clients := make(map[int]chan Message)
    for id, ch := range s.clients {
        clients[id] = ch
    }
    s.mu.RUnlock()
    
    broadcastMsg := Message{
        Type:    "broadcast",
        Content: msg.Content,
        ID:      msg.ID,
    }
    
    for id, ch := range clients {
        select {
        case ch <- broadcastMsg:
            fmt.Printf("广播消息发送给客户端 %d\n", id)
        default:
            fmt.Printf("客户端 %d 通道已满\n", id)
        }
    }
    
    return Message{
        Type:    "broadcast_response",
        Content: "广播完成",
        ID:      msg.ID,
    }
}

func (s *Server) Start() {
    fmt.Println("服务器启动...")
    
    // 模拟服务器运行
    go func() {
        for {
            time.Sleep(10 * time.Second)
            fmt.Printf("服务器运行中,当前客户端数: %d\n", len(s.clients))
        }
    }()
}

9.3 主程序

// main.go
package main

import (
    "fmt"
    "sync"
    "time"
)

func main() {
    server := NewServer()
    server.Start()
    
    var wg sync.WaitGroup
    
    // 创建多个客户端
    for i := 0; i < 3; i++ {
        wg.Add(1)
        go func(clientID int) {
            defer wg.Done()
            client := NewClient(server, clientID)
            client.Start()
        }(i)
    }
    
    wg.Wait()
    fmt.Println("所有客户端已退出")
}

type Client struct {
    server   *Server
    id       int
    stopChan chan struct{}
}

func NewClient(server *Server, id int) *Client {
    return &Client{
        server:   server,
        id:       id,
        stopChan: make(chan struct{}),
    }
}

func (c *Client) Start() {
    clientID := c.server.RegisterClient()
    defer c.server.UnregisterClient(clientID)
    
    fmt.Printf("客户端 %d 启动\n", clientID)
    
    // 发送echo消息
    go func() {
        time.Sleep(time.Duration(clientID+1) * time.Second)
        echoMsg := Message{
            Type:    "echo",
            Content: fmt.Sprintf("来自客户端 %d 的消息", clientID),
            ID:      clientID,
        }
        c.server.SendMessage(clientID, echoMsg)
    }()
    
    // 发送广播消息
    go func() {
        time.Sleep(time.Duration(clientID+2) * time.Second)
        broadcastMsg := Message{
            Type:    "broadcast",
            Content: fmt.Sprintf("客户端 %d 的广播消息", clientID),
            ID:      clientID,
        }
        c.server.SendMessage(clientID, broadcastMsg)
    }()
    
    // 监听消息
    go func() {
        s.mu.RLock()
        ch := s.clients[clientID]
        s.mu.RUnlock()
        
        for msg := range ch {
            fmt.Printf("客户端 %d 收到消息: %+v\n", clientID, msg)
        }
    }()
    
    // 运行一段时间后退出
    time.Sleep(5 * time.Second)
    fmt.Printf("客户端 %d 退出\n", clientID)
}

9.4 运行程序

# 运行完整示例
go run main.go server.go ipc.go

预期输出:

服务器启动...
客户端 0 已注册
客户端 1 已注册
客户端 2 已注册
客户端 0 启动
客户端 1 启动
客户端 2 启动
客户端 0 收到消息: {Type:echo_response Content:来自客户端 0 的消息 ID:0}
客户端 1 收到消息: {Type:echo_response Content:来自客户端 1 的消息 ID:1}
客户端 2 收到消息: {Type:echo_response Content:来自客户端 2 的消息 ID:2}
广播消息发送给客户端 0
广播消息发送给客户端 1
广播消息发送给客户端 2
客户端 0 收到消息: {Type:broadcast Content:客户端 0 的广播消息 ID:0}
客户端 1 收到消息: {Type:broadcast Content:客户端 0 的广播消息 ID:0}
客户端 2 收到消息: {Type:broadcast Content:客户端 0 的广播消息 ID:0}
...
客户端 0 退出
客户端 1 退出
客户端 2 退出
所有客户端已退出

练习题

package main

import (
	"fmt"
	//"math"
	"math/rand"
	"runtime"
	"sync"
	//"sync/atomic"
	"time"
)

// ================== 4.1 并发基础 ==================
// Exercise: 演示并发与并行的区别,使用两个函数:一个CPU密集型,一个IO密集型。
func cpuIntensive(id int, wg *sync.WaitGroup) {
	defer wg.Done()
	result := 0
	for i := 0; i < 10000000; i++ {
		result += i * i
	}
	fmt.Printf("CPU Intensive Task %d Done, Result: %d\n", id, result)
}

func ioIntensive(id int, wg *sync.WaitGroup) {
	defer wg.Done()
	time.Sleep(2 * time.Second) // 模拟IO操作
	fmt.Printf("IO Intensive Task %d Done\n", id)
}

func exercise4_1() {
	fmt.Println("\n=== 4.1 并发基础 ===")
	var wg sync.WaitGroup

	start := time.Now()

	// 并发执行(不一定是并行)
	for i := 1; i <= 2; i++ {
		wg.Add(1)
		go cpuIntensive(i, &wg)
	}
	for i := 1; i <= 2; i++ {
		wg.Add(1)
		go ioIntensive(i, &wg)
	}

	wg.Wait()
	fmt.Printf("Total time: %.2fs\n", time.Since(start).Seconds())
}

// ================== 4.2 协程 ==================
// Go的协程由runtime管理,用户无需直接操作。
// Exercise: 使用go关键字启动多个轻量级协程。
func exercise4_2() {
	fmt.Println("\n=== 4.2 协程 ===")
	for i := 1; i <= 3; i++ {
		go func(id int) {
			fmt.Printf("Goroutine %d is running\n", id)
		}(i)
	}
	time.Sleep(100 * time.Millisecond) // 等待协程执行
}

// ================== 4.3 goroutine ==================
// Exercise: 演示goroutine的创建、调度和退出。
func worker(id int, quit chan bool) {
	fmt.Printf("Worker %d started\n", id)
	for {
		select {
		case <-quit:
			fmt.Printf("Worker %d stopped\n", id)
			return
		default:
			fmt.Printf("Worker %d is working...\n", id)
			time.Sleep(500 * time.Millisecond)
		}
	}
}

func exercise4_3() {
	fmt.Println("\n=== 4.3 goroutine ===")
	quit := make(chan bool)

	for i := 1; i <= 2; i++ {
		go worker(i, quit)
	}

	time.Sleep(2 * time.Second)
	close(quit) // 通知所有worker退出
	time.Sleep(100 * time.Millisecond)
}

// ================== 4.4 并发通信 ==================
// Exercise: 使用channel在goroutine间传递数据。
func producer(ch chan<- int) {
	for i := 1; i <= 5; i++ {
		ch <- i
		fmt.Printf("Produced: %d\n", i)
		time.Sleep(100 * time.Millisecond)
	}
}

func consumer(ch <-chan int, id int) {
	for num := range ch {
		fmt.Printf("Consumer %d received: %d\n", id, num)
		time.Sleep(200 * time.Millisecond)
	}
}

func exercise4_4() {
	fmt.Println("\n=== 4.4 并发通信 ===")
	ch := make(chan int)

	go producer(ch)
	go consumer(ch, 1)
	go consumer(ch, 2)

	time.Sleep(2 * time.Second)
	close(ch)
	time.Sleep(100 * time.Millisecond)
}

// ================== 4.5 channel ==================

// 4.5.1 基本语法
func exercise4_5_1() {
	fmt.Println("\n=== 4.5.1 基本语法 ===")
	ch := make(chan string)
	go func() {
		ch <- "Hello from goroutine!" // 发送
	}()
	msg := <-ch // 接收
	fmt.Println("Received:", msg)
}

// 4.5.2 select
func exercise4_5_2() {
	fmt.Println("\n=== 4.5.2 select ===")
	ch1 := make(chan string)
	ch2 := make(chan string)

	go func() {
		time.Sleep(1 * time.Second)
		ch1 <- "from ch1"
	}()
	go func() {
		time.Sleep(1500 * time.Millisecond)
		ch2 <- "from ch2"
	}()

	for i := 0; i < 2; i++ {
		select {
		case msg1 := <-ch1:
			fmt.Println("Received", msg1)
		case msg2 := <-ch2:
			fmt.Println("Received", msg2)
		}
	}
}

// 4.5.3 缓冲机制
func exercise4_5_3() {
	fmt.Println("\n=== 4.5.3 缓冲机制 ===")
	ch := make(chan int, 3) // 缓冲大小为3

	// 可以连续发送,无需立即接收
	for i := 1; i <= 3; i++ {
		ch <- i
		fmt.Printf("Sent: %d (len=%d, cap=%d)\n", i, len(ch), cap(ch))
	}

	// 接收
	for i := 1; i <= 3; i++ {
		num := <-ch
		fmt.Printf("Received: %d (len=%d, cap=%d)\n", num, len(ch), cap(ch))
	}
}

// 4.5.4 超时机制
func exercise4_5_4() {
	fmt.Println("\n=== 4.5.4 超时机制 ===")
	ch := make(chan int)

	go func() {
		time.Sleep(2 * time.Second)
		ch <- 42
	}()

	select {
	case res := <-ch:
		fmt.Println("Result:", res)
	case <-time.After(1 * time.Second):
		fmt.Println("Timeout! No response within 1s")
	}
}

// 4.5.5 channel的传递
func sendChan(ch chan<- chan int) {
	subCh := make(chan int)
	ch <- subCh // 传递channel
}

func exercise4_5_5() {
	fmt.Println("\n=== 4.5.5 channel的传递 ===")
	chOfCh := make(chan chan int)

	go sendChan(chOfCh)

	subCh := <-chOfCh
	subCh <- 100
	fmt.Println("Received via passed channel:", <-subCh)
}

// 4.5.6 单向channel
func sendOnly(ch chan<- int) {
	ch <- 99
}

func receiveOnly(ch <-chan int) {
	fmt.Println("Received in receiveOnly:", <-ch)
}

func exercise4_5_6() {
	fmt.Println("\n=== 4.5.6 单向channel ===")
	ch := make(chan int)
	go sendOnly(ch)
	go receiveOnly(ch)
	time.Sleep(100 * time.Millisecond)
}

// 4.5.7 关闭channel
func exercise4_5_7() {
	fmt.Println("\n=== 4.5.7 关闭channel ===")
	ch := make(chan int, 2)
	ch <- 1
	ch <- 2
	close(ch)

	// 正常接收
	for i := 0; i < 2; i++ {
		if num, ok := <-ch; ok {
			fmt.Printf("Received: %d, ok=%t\n", num, ok)
		}
	}

	// 接收已关闭的channel
	num, ok := <-ch
	fmt.Printf("After close: %d, ok=%t\n", num, ok)

	// 多次接收关闭的channel会返回零值
	fmt.Printf("Zero value: %d\n", <-ch)
}

// ================== 4.6 多核并行化 ==================
func parallelSum(arr []int, result chan<- int) {
	sum := 0
	for _, v := range arr {
		sum += v
	}
	result <- sum
}

func exercise4_6() {
	fmt.Println("\n=== 4.6 多核并行化 ===")
	const numCPU = 4
	arr := make([]int, 1000000)
	for i := range arr {
		arr[i] = rand.Intn(100)
	}

	result := make(chan int, numCPU)
	chunkSize := len(arr) / numCPU

	start := time.Now()

	for i := 0; i < numCPU; i++ {
		startIdx := i * chunkSize
		endIdx := startIdx + chunkSize
		if i == numCPU-1 {
			endIdx = len(arr) // 最后一个goroutine处理剩余部分
		}
		go parallelSum(arr[startIdx:endIdx], result)
	}

	total := 0
	for i := 0; i < numCPU; i++ {
		total += <-result
	}

	fmt.Printf("Parallel sum: %d, Time: %.2fs\n", total, time.Since(start).Seconds())
	fmt.Printf("Using %d CPUs\n", runtime.NumCPU())
}

// ================== 4.7 出让时间片 ==================
func yieldTask(id int, wg *sync.WaitGroup) {
	defer wg.Done()
	for i := 0; i < 3; i++ {
		fmt.Printf("Task %d: step %d\n", id, i)
		runtime.Gosched() // 显式出让时间片
	}
}

func exercise4_7() {
	fmt.Println("\n=== 4.7 出让时间片 ===")
	var wg sync.WaitGroup
	for i := 1; i <= 3; i++ {
		wg.Add(1)
		go yieldTask(i, &wg)
	}
	wg.Wait()
}

// ================== 4.8 同步 ==================

// 4.8.1 同步锁
type Counter struct {
	mu    sync.Mutex
	value int
}

func (c *Counter) Increment() {
	c.mu.Lock()
	defer c.mu.Unlock()
	c.value++
}

func (c *Counter) Value() int {
	c.mu.Lock()
	defer c.mu.Unlock()
	return c.value
}

func exercise4_8_1() {
	fmt.Println("\n=== 4.8.1 同步锁 ===")
	var counter Counter
	var wg sync.WaitGroup

	for i := 0; i < 1000; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			counter.Increment()
		}()
	}

	wg.Wait()
	fmt.Printf("Final counter value: %d (should be 1000)\n", counter.Value())
}

// 4.8.2 全局唯一性操作
var once sync.Once
var config string

func loadConfig() {
	fmt.Println("Loading configuration...")
	time.Sleep(500 * time.Millisecond)
	config = "AppConfig-v1"
}

func getConfig() string {
	once.Do(loadConfig) // 确保只执行一次
	return config
}

func exercise4_8_2() {
	fmt.Println("\n=== 4.8.2 全局唯一性操作 ===")
	var wg sync.WaitGroup

	for i := 1; i <= 5; i++ {
		wg.Add(1)
		go func(id int) {
			defer wg.Done()
			cfg := getConfig()
			fmt.Printf("Goroutine %d got config: %s\n", id, cfg)
		}(i)
	}

	wg.Wait()
}

// ================== 4.9 完整示例 ==================

// 4.9.1 简单IPC框架
type Message struct {
	From    string
	To      string
	Content string
}

type IPC struct {
	mu      sync.RWMutex
	clients map[string]chan Message
}

func NewIPC() *IPC {
	return &IPC{
		clients: make(map[string]chan Message),
	}
}

func (i *IPC) Register(name string) <-chan Message {
	i.mu.Lock()
	defer i.mu.Unlock()
	ch := make(chan Message, 100)
	i.clients[name] = ch
	fmt.Printf("Client %s registered\n", name)
	return ch
}

func (i *IPC) Unregister(name string) {
	i.mu.Lock()
	defer i.mu.Unlock()
	if ch, ok := i.clients[name]; ok {
		close(ch)
		delete(i.clients, name)
		fmt.Printf("Client %s unregistered\n", name)
	}
}

func (i *IPC) Send(msg Message) error {
	i.mu.RLock()
	defer i.mu.RUnlock()

	if ch, ok := i.clients[msg.To]; ok {
		select {
		case ch <- msg:
			return nil
		default:
			return fmt.Errorf("recipient %s's inbox is full", msg.To)
		}
	}
	return fmt.Errorf("recipient %s not found", msg.To)
}

// 4.9.2 中央服务器
func server(ipc *IPC, stop chan struct{}) {
	ticker := time.NewTicker(1 * time.Second)
	defer ticker.Stop()

	for {
		select {
		case <-ticker.C:
			fmt.Println("Server heartbeat...")
		case <-stop:
			fmt.Println("Server shutting down...")
			return
		}
	}
}

// 4.9.3 主程序
func client(ipc *IPC, name string, stop chan struct{}) {
	inbox := ipc.Register(name)
	defer ipc.Unregister(name)

	ticker := time.NewTicker(2 * time.Second)
	defer ticker.Stop()

	for {
		select {
		case msg, ok := <-inbox:
			if !ok {
				fmt.Printf("Client %s inbox closed\n", name)
				return
			}
			fmt.Printf("Client %s received: [%s->%s] %s\n", name, msg.From, msg.To, msg.Content)
		case <-ticker.C:
			// 发送心跳消息
			if err := ipc.Send(Message{From: name, To: "server", Content: "ping"}); err != nil {
				fmt.Printf("Client %s send failed: %v\n", name, err)
			}
		case <-stop:
			fmt.Printf("Client %s shutting down\n", name)
			return
		}
	}
}

// 4.9.4 运行程序
func exercise4_9() {
	fmt.Println("\n=== 4.9 完整示例 ===")
	ipc := NewIPC()
	serverStop := make(chan struct{})
	clientStop := make(chan struct{})

	// 启动服务器
	go server(ipc, serverStop)

	// 启动客户端
	go client(ipc, "Alice", clientStop)
	go client(ipc, "Bob", clientStop)

	// 运行10秒
	time.Sleep(10 * time.Second)

	// 关闭所有
	close(serverStop)
	close(clientStop)

	// 清理
	time.Sleep(100 * time.Millisecond)
	fmt.Println("All components stopped")
}

// 主函数:运行所有练习
func main() {
	rand.Seed(time.Now().UnixNano())
	fmt.Println("Go Concurrency Programming Exercises")
	fmt.Println("=====================================")

	exercise4_1()
	exercise4_2()
	exercise4_3()
	exercise4_4()
	exercise4_5_1()
	exercise4_5_2()
	exercise4_5_3()
	exercise4_5_4()
	exercise4_5_5()
	exercise4_5_6()
	exercise4_5_7()
	exercise4_6()
	exercise4_7()
	exercise4_8_1()
	exercise4_8_2()
	exercise4_9()

	fmt.Println("\nAll exercises completed!")
}