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!")
}