From 61e51ad0142d937577526c741ca67621c71fc648 Mon Sep 17 00:00:00 2001 From: estel <690930@qq.com> Date: Sun, 24 Aug 2025 11:24:52 +0800 Subject: [PATCH] =?UTF-8?q?=E7=BB=A7=E7=BB=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .kiro/specs/golang-learning-guide/tasks.md | 8 +- .../05-interfaces/01-basic-interfaces.go | 1340 ++++++++++++++ .../05-interfaces/02-empty-interface.go | 981 +++++++++++ .../05-interfaces/03-type-assertions.go | 1058 +++++++++++ .../06-concurrency/01-goroutines.go | 738 ++++++++ golang-learning/06-concurrency/02-channels.go | 840 +++++++++ golang-learning/06-concurrency/03-select.go | 880 ++++++++++ .../06-concurrency/04-sync-package.go | 1183 +++++++++++++ .../06-concurrency/05-worker-pools.go | 1561 +++++++++++++++++ .../07-error-handling/01-basic-errors.go | 957 ++++++++++ .../07-error-handling/02-custom-errors.go | 1071 +++++++++++ .../07-error-handling/03-panic-recover.go | 941 ++++++++++ 12 files changed, 11554 insertions(+), 4 deletions(-) create mode 100644 golang-learning/05-interfaces/01-basic-interfaces.go create mode 100644 golang-learning/05-interfaces/02-empty-interface.go create mode 100644 golang-learning/05-interfaces/03-type-assertions.go create mode 100644 golang-learning/06-concurrency/01-goroutines.go create mode 100644 golang-learning/06-concurrency/02-channels.go create mode 100644 golang-learning/06-concurrency/03-select.go create mode 100644 golang-learning/06-concurrency/04-sync-package.go create mode 100644 golang-learning/06-concurrency/05-worker-pools.go create mode 100644 golang-learning/07-error-handling/01-basic-errors.go create mode 100644 golang-learning/07-error-handling/02-custom-errors.go create mode 100644 golang-learning/07-error-handling/03-panic-recover.go diff --git a/.kiro/specs/golang-learning-guide/tasks.md b/.kiro/specs/golang-learning-guide/tasks.md index 7881efc..07143d8 100644 --- a/.kiro/specs/golang-learning-guide/tasks.md +++ b/.kiro/specs/golang-learning-guide/tasks.md @@ -59,27 +59,27 @@ - _需求: 4.1, 4.2, 4.3_ - [ ] 6. 实现接口学习模块 -- [ ] 6.1 创建接口基础示例 +- [x] 6.1 创建接口基础示例 - 编写 05-interfaces/01-basic-interfaces.go,展示接口的定义和实现 - 编写 05-interfaces/02-empty-interface.go,演示空接口的使用 - 编写 05-interfaces/03-type-assertions.go,展示类型断言的使用 - _需求: 3.2_ - [ ] 7. 实现并发编程学习模块 -- [ ] 7.1 创建 Goroutine 和 Channel 示例 +- [x] 7.1 创建 Goroutine 和 Channel 示例 - 编写 06-concurrency/01-goroutines.go,展示 goroutine 的基础使用 - 编写 06-concurrency/02-channels.go,演示 channel 的各种操作 - 编写 06-concurrency/03-select.go,展示 select 语句的使用 - _需求: 5.1, 5.2, 5.3_ -- [ ] 7.2 创建同步和高级并发示例 +- [x] 7.2 创建同步和高级并发示例 - 编写 06-concurrency/04-sync-package.go,展示 sync 包的使用方法 - 编写 06-concurrency/05-worker-pools.go,演示工作池模式 - 提供避免竞态条件的最佳实践示例 - _需求: 5.1, 5.2, 5.3_ - [ ] 8. 实现错误处理学习模块 -- [ ] 8.1 创建错误处理示例 +- [x] 8.1 创建错误处理示例 - 编写 07-error-handling/01-basic-errors.go,展示基本错误处理 - 编写 07-error-handling/02-custom-errors.go,演示自定义错误类型 - 编写 07-error-handling/03-panic-recover.go,展示 panic 和 recover 的使用 diff --git a/golang-learning/05-interfaces/01-basic-interfaces.go b/golang-learning/05-interfaces/01-basic-interfaces.go new file mode 100644 index 0000000..e94f24a --- /dev/null +++ b/golang-learning/05-interfaces/01-basic-interfaces.go @@ -0,0 +1,1340 @@ +/* +01-basic-interfaces.go - Go 语言基础接口详解 + +学习目标: +1. 理解接口的概念和作用 +2. 掌握接口的定义和实现 +3. 学会接口的多态特性 +4. 了解接口的组合 +5. 掌握接口的实际应用场景 + +知识点: +- 接口的定义和特性 +- 接口的实现(隐式实现) +- 接口的多态性 +- 接口的组合 +- 接口与结构体的关系 +- 接口的最佳实践 +*/ + +package main + +import ( + "fmt" +) + +func main() { + fmt.Println("=== Go 语言基础接口详解 ===\n") + + // 演示接口的基本概念 + demonstrateBasicInterfaces() + + // 演示接口的实现 + demonstrateInterfaceImplementation() + + // 演示接口的多态性 + demonstratePolymorphism() + + // 演示接口的组合 + demonstrateInterfaceComposition() + + // 演示接口与结构体 + demonstrateInterfacesWithStructs() + + // 演示接口的高级用法 + demonstrateAdvancedInterfaceUsage() + + // 演示接口的实际应用 + demonstratePracticalApplications() +} + +// demonstrateBasicInterfaces 演示接口的基本概念 +func demonstrateBasicInterfaces() { + fmt.Println("1. 接口的基本概念:") + + // 接口的基本特性 + fmt.Printf(" 接口的基本特性:\n") + fmt.Printf(" - 定义方法签名的集合\n") + fmt.Printf(" - 隐式实现,无需显式声明\n") + fmt.Printf(" - 支持多态和抽象\n") + fmt.Printf(" - 接口类型的零值是 nil\n") + fmt.Printf(" - 接口可以嵌入其他接口\n") + + // 基本接口示例 + fmt.Printf(" 基本接口示例:\n") + + // 创建不同的形状 + var shape Shape + + // 圆形 + circle := Circle{Radius: 5} + shape = circle + fmt.Printf(" 圆形面积: %.2f\n", shape.Area()) + fmt.Printf(" 圆形周长: %.2f\n", shape.Perimeter()) + + // 矩形 + rectangle := Rectangle{Width: 4, Height: 6} + shape = rectangle + fmt.Printf(" 矩形面积: %.2f\n", shape.Area()) + fmt.Printf(" 矩形周长: %.2f\n", shape.Perimeter()) + + // 三角形 + triangle := Triangle{Base: 8, Height: 6} + shape = triangle + fmt.Printf(" 三角形面积: %.2f\n", shape.Area()) + fmt.Printf(" 三角形周长: %.2f\n", shape.Perimeter()) + + // 接口的零值 + fmt.Printf(" 接口的零值:\n") + var nilShape Shape + fmt.Printf(" nil 接口: %v\n", nilShape) + fmt.Printf(" nil 接口 == nil: %t\n", nilShape == nil) + + // 检查接口是否为 nil + if nilShape == nil { + fmt.Printf(" 接口为 nil,不能调用方法\n") + } + + fmt.Println() +} + +// demonstrateInterfaceImplementation 演示接口的实现 +func demonstrateInterfaceImplementation() { + fmt.Println("2. 接口的实现:") + + fmt.Printf(" Go 语言的接口实现是隐式的\n") + fmt.Printf(" 只要类型实现了接口的所有方法,就自动实现了该接口\n") + + // 演示隐式实现 + fmt.Printf(" 隐式实现示例:\n") + + // Writer 接口的不同实现 + var writer Writer + + // 文件写入器 + fileWriter := &FileWriter{filename: "output.txt"} + writer = fileWriter + writer.Write([]byte("Hello, File!")) + + // 控制台写入器 + consoleWriter := &ConsoleWriter{} + writer = consoleWriter + writer.Write([]byte("Hello, Console!")) + + // 内存写入器 + memoryWriter := &MemoryWriter{} + writer = memoryWriter + writer.Write([]byte("Hello, Memory!")) + fmt.Printf(" 内存写入器内容: %s\n", string(memoryWriter.buffer)) + + // 接口方法的调用 + fmt.Printf(" 接口方法调用:\n") + + // 创建不同的动物 + animals := []Animal{ + Dog{Name: "旺财"}, + Cat{Name: "咪咪"}, + Bird{Name: "小鸟"}, + } + + for _, animal := range animals { + fmt.Printf(" %s: %s\n", animal.Name(), animal.Sound()) + animal.Move() + } + + fmt.Println() +} + +// demonstratePolymorphism 演示接口的多态性 +func demonstratePolymorphism() { + fmt.Println("3. 接口的多态性:") + + fmt.Printf(" 多态允许不同类型以统一的方式处理\n") + + // 形状多态示例 + fmt.Printf(" 形状多态示例:\n") + + shapes := []Shape{ + Circle{Radius: 3}, + Rectangle{Width: 4, Height: 5}, + Triangle{Base: 6, Height: 4}, + Circle{Radius: 2}, + } + + totalArea := 0.0 + for i, shape := range shapes { + area := shape.Area() + fmt.Printf(" 形状 %d 面积: %.2f\n", i+1, area) + totalArea += area + } + fmt.Printf(" 总面积: %.2f\n", totalArea) + + // 支付方式多态示例 + fmt.Printf(" 支付方式多态示例:\n") + + paymentMethods := []PaymentMethod{ + CreditCard{CardNumber: "1234-5678-9012-3456", Balance: 1000}, + PayPal{Email: "user@example.com", Balance: 500}, + Cash{Amount: 200}, + } + + totalAmount := 300.0 + for _, method := range paymentMethods { + fmt.Printf(" 使用 %s 支付:\n", method.GetName()) + if method.Pay(totalAmount) { + fmt.Printf(" 支付成功!\n") + break + } else { + fmt.Printf(" 支付失败,余额不足\n") + } + } + + // 排序接口多态 + fmt.Printf(" 排序接口多态:\n") + + // 整数排序 + numbers := IntSlice{64, 34, 25, 12, 22, 11, 90} + fmt.Printf(" 排序前: %v\n", numbers) + Sort(numbers) + fmt.Printf(" 排序后: %v\n", numbers) + + // 字符串排序 + words := StringSlice{"banana", "apple", "cherry", "date"} + fmt.Printf(" 排序前: %v\n", words) + Sort(words) + fmt.Printf(" 排序后: %v\n", words) + + fmt.Println() +} + +// demonstrateInterfaceComposition 演示接口的组合 +func demonstrateInterfaceComposition() { + fmt.Println("4. 接口的组合:") + + fmt.Printf(" 接口可以嵌入其他接口,实现接口组合\n") + + // 读写器组合示例 + fmt.Printf(" 读写器组合示例:\n") + + // 文件读写器实现了 ReadWriter 接口 + var rw ReadWriter = &FileReadWriter{ + filename: "test.txt", + content: "Initial content", + } + + // 写入数据 + data := []byte("Hello, ReadWriter!") + n := rw.Write(data) + fmt.Printf(" 写入 %d 字节\n", n) + + // 读取数据 + buffer := make([]byte, 50) + n = rw.Read(buffer) + fmt.Printf(" 读取 %d 字节: %s\n", n, string(buffer[:n])) + + // 关闭资源 + if closer, ok := rw.(Closer); ok { + closer.Close() + fmt.Printf(" 资源已关闭\n") + } + + // 多接口组合 + fmt.Printf(" 多接口组合示例:\n") + + // 多媒体播放器 + var player MediaPlayer = &VideoPlayer{ + filename: "movie.mp4", + volume: 80, + position: 0, + } + + // 播放控制 + player.Play() + player.SetVolume(90) + player.Seek(120) // 跳转到2分钟 + + // 如果支持视频控制 + if videoCtrl, ok := player.(VideoController); ok { + videoCtrl.SetBrightness(75) + videoCtrl.SetContrast(85) + fmt.Printf(" 视频控制设置完成\n") + } + + player.Pause() + player.Stop() + + fmt.Println() +}// demons +trateInterfacesWithStructs 演示接口与结构体 +func demonstrateInterfacesWithStructs() { + fmt.Println("5. 接口与结构体:") + + // 结构体实现接口 + fmt.Printf(" 结构体实现接口:\n") + + // 创建员工 + employees := []Employee{ + Developer{ + Name: "Alice", + Language: "Go", + Experience: 5, + }, + Manager{ + Name: "Bob", + Department: "Engineering", + TeamSize: 10, + }, + Designer{ + Name: "Charlie", + Tool: "Figma", + Portfolio: []string{"App UI", "Web Design"}, + }, + } + + // 计算总薪资 + totalSalary := 0.0 + for _, emp := range employees { + salary := emp.GetSalary() + fmt.Printf(" %s (%s): $%.2f\n", emp.GetName(), emp.GetRole(), salary) + totalSalary += salary + } + fmt.Printf(" 总薪资: $%.2f\n", totalSalary) + + // 让员工工作 + fmt.Printf(" 员工工作:\n") + for _, emp := range employees { + emp.Work() + } + + // 接口作为结构体字段 + fmt.Printf(" 接口作为结构体字段:\n") + + // 创建通知系统 + notifier := NotificationSystem{ + providers: []NotificationProvider{ + EmailProvider{SMTPServer: "smtp.example.com"}, + SMSProvider{APIKey: "sms-api-key"}, + PushProvider{AppID: "push-app-id"}, + }, + } + + // 发送通知 + message := "系统维护通知:服务将在今晚10点进行维护" + notifier.SendNotification(message) + + fmt.Println() +} + +// demonstrateAdvancedInterfaceUsage 演示接口的高级用法 +func demonstrateAdvancedInterfaceUsage() { + fmt.Println("6. 接口的高级用法:") + + // 接口作为参数 + fmt.Printf(" 接口作为参数:\n") + + shapes := []Shape{ + Circle{Radius: 2}, + Rectangle{Width: 3, Height: 4}, + Triangle{Base: 5, Height: 6}, + } + + // 计算总面积 + total := calculateTotalArea(shapes) + fmt.Printf(" 所有形状总面积: %.2f\n", total) + + // 找出最大面积的形状 + largest := findLargestShape(shapes) + fmt.Printf(" 最大面积: %.2f\n", largest.Area()) + + // 接口作为返回值 + fmt.Printf(" 接口作为返回值:\n") + + // 创建不同类型的数据库连接 + mysqlDB := createDatabase("mysql") + postgresDB := createDatabase("postgres") + redisDB := createDatabase("redis") + + // 使用数据库 + mysqlDB.Connect() + mysqlDB.Query("SELECT * FROM users") + mysqlDB.Close() + + postgresDB.Connect() + postgresDB.Query("SELECT * FROM products") + postgresDB.Close() + + redisDB.Connect() + redisDB.Query("GET user:123") + redisDB.Close() + + // 接口切片 + fmt.Printf(" 接口切片:\n") + + var items []fmt.Stringer + items = append(items, Circle{Radius: 3}) + items = append(items, Rectangle{Width: 4, Height: 5}) + items = append(items, Person{Name: "Alice", Age: 30}) + + fmt.Printf(" 接口切片内容:\n") + for i, item := range items { + fmt.Printf(" %d: %s\n", i+1, item.String()) + } + + // 接口嵌套 + fmt.Printf(" 接口嵌套:\n") + + // HTTP 服务器 + server := &HTTPServer{ + port: 8080, + routes: map[string]string{ + "/": "Welcome", + "/about": "About Us", + }, + } + + // 启动服务器 + server.Start() + server.HandleRequest("/") + server.HandleRequest("/about") + server.Stop() + + fmt.Println() +} + +// demonstratePracticalApplications 演示接口的实际应用 +func demonstratePracticalApplications() { + fmt.Println("7. 接口的实际应用:") + + // 应用1: 插件系统 + fmt.Printf(" 应用1 - 插件系统:\n") + + pluginManager := PluginManager{} + + // 注册插件 + pluginManager.RegisterPlugin(&LoggingPlugin{}) + pluginManager.RegisterPlugin(&CachePlugin{}) + pluginManager.RegisterPlugin(&SecurityPlugin{}) + + // 执行插件 + pluginManager.ExecutePlugins("用户登录") + + // 应用2: 策略模式 + fmt.Printf(" 应用2 - 策略模式:\n") + + // 不同的排序策略 + data := []int{64, 34, 25, 12, 22, 11, 90} + + sorter := DataSorter{data: make([]int, len(data))} + + // 使用冒泡排序 + copy(sorter.data, data) + sorter.SetStrategy(&BubbleSort{}) + fmt.Printf(" 原始数据: %v\n", data) + sorter.Sort() + fmt.Printf(" 冒泡排序: %v\n", sorter.data) + + // 使用快速排序 + copy(sorter.data, data) + sorter.SetStrategy(&QuickSort{}) + sorter.Sort() + fmt.Printf(" 快速排序: %v\n", sorter.data) + + // 应用3: 观察者模式 + fmt.Printf(" 应用3 - 观察者模式:\n") + + // 创建主题 + subject := &NewsAgency{} + + // 创建观察者 + tv := &TVChannel{name: "新闻频道"} + radio := &RadioStation{name: "广播电台"} + website := &NewsWebsite{name: "新闻网站"} + + // 订阅 + subject.Subscribe(tv) + subject.Subscribe(radio) + subject.Subscribe(website) + + // 发布新闻 + subject.PublishNews("重大新闻:Go 语言发布新版本!") + + // 应用4: 工厂模式 + fmt.Printf(" 应用4 - 工厂模式:\n") + + // 创建不同类型的日志记录器 + loggers := []Logger{ + CreateLogger("file"), + CreateLogger("console"), + CreateLogger("database"), + } + + message := "这是一条测试日志" + for _, logger := range loggers { + logger.Log(message) + } + + // 应用5: 适配器模式 + fmt.Printf(" 应用5 - 适配器模式:\n") + + // 旧系统 + oldSystem := &OldPaymentSystem{} + + // 使用适配器 + adapter := &PaymentAdapter{oldSystem: oldSystem} + + // 通过新接口使用旧系统 + var newPayment NewPaymentInterface = adapter + newPayment.ProcessPayment(100.0, "USD") + + fmt.Println() +} + +// ========== 接口定义 ========== + +// 基本形状接口 +type Shape interface { + Area() float64 + Perimeter() float64 +} + +// 写入器接口 +type Writer interface { + Write([]byte) int +} + +// 动物接口 +type Animal interface { + Name() string + Sound() string + Move() +} + +// 支付方法接口 +type PaymentMethod interface { + Pay(amount float64) bool + GetName() string +} + +// 排序接口 +type Sortable interface { + Len() int + Less(i, j int) bool + Swap(i, j int) +} + +// 读取器接口 +type Reader interface { + Read([]byte) int +} + +// 读写器接口(组合接口) +type ReadWriter interface { + Reader + Writer +} + +// 关闭器接口 +type Closer interface { + Close() +} + +// 媒体播放器接口 +type MediaPlayer interface { + Play() + Pause() + Stop() + SetVolume(volume int) + Seek(position int) +} + +// 视频控制器接口 +type VideoController interface { + SetBrightness(brightness int) + SetContrast(contrast int) +} + +// 员工接口 +type Employee interface { + GetName() string + GetRole() string + GetSalary() float64 + Work() +} + +// 通知提供者接口 +type NotificationProvider interface { + SendNotification(message string) error +} + +// 数据库接口 +type Database interface { + Connect() error + Query(sql string) ([]map[string]interface{}, error) + Close() error +} + +// 服务器接口 +type Server interface { + Start() error + Stop() error + HandleRequest(path string) string +} + +// 插件接口 +type Plugin interface { + Name() string + Execute(data interface{}) error +} + +// 排序策略接口 +type SortStrategy interface { + Sort([]int) +} + +// 观察者接口 +type Observer interface { + Update(news string) +} + +// 主题接口 +type Subject interface { + Subscribe(observer Observer) + Unsubscribe(observer Observer) + Notify(news string) +} + +// 日志记录器接口 +type Logger interface { + Log(message string) +} + +// 新支付接口 +type NewPaymentInterface interface { + ProcessPayment(amount float64, currency string) bool +} + +// ========== 结构体实现 ========== + +// 圆形 +type Circle struct { + Radius float64 +} + +func (c Circle) Area() float64 { + return math.Pi * c.Radius * c.Radius +} + +func (c Circle) Perimeter() float64 { + return 2 * math.Pi * c.Radius +} + +func (c Circle) String() string { + return fmt.Sprintf("Circle(radius=%.1f)", c.Radius) +} + +// 矩形 +type Rectangle struct { + Width, Height float64 +} + +func (r Rectangle) Area() float64 { + return r.Width * r.Height +} + +func (r Rectangle) Perimeter() float64 { + return 2 * (r.Width + r.Height) +} + +func (r Rectangle) String() string { + return fmt.Sprintf("Rectangle(%.1fx%.1f)", r.Width, r.Height) +} + +// 三角形 +type Triangle struct { + Base, Height float64 +} + +func (t Triangle) Area() float64 { + return 0.5 * t.Base * t.Height +} + +func (t Triangle) Perimeter() float64 { + // 假设是等腰三角形 + side := math.Sqrt((t.Base/2)*(t.Base/2) + t.Height*t.Height) + return t.Base + 2*side +} + +func (t Triangle) String() string { + return fmt.Sprintf("Triangle(base=%.1f, height=%.1f)", t.Base, t.Height) +} + +// 文件写入器 +type FileWriter struct { + filename string +} + +func (fw *FileWriter) Write(data []byte) int { + fmt.Printf(" 写入文件 %s: %s\n", fw.filename, string(data)) + return len(data) +} + +// 控制台写入器 +type ConsoleWriter struct{} + +func (cw *ConsoleWriter) Write(data []byte) int { + fmt.Printf(" 控制台输出: %s\n", string(data)) + return len(data) +} + +// 内存写入器 +type MemoryWriter struct { + buffer []byte +} + +func (mw *MemoryWriter) Write(data []byte) int { + mw.buffer = append(mw.buffer, data...) + fmt.Printf(" 写入内存: %s\n", string(data)) + return len(data) +} + +// 狗 +type Dog struct { + Name string +} + +func (d Dog) Name() string { return d.Name } +func (d Dog) Sound() string { return "汪汪" } +func (d Dog) Move() { fmt.Printf(" %s 在跑步\n", d.Name) } + +// 猫 +type Cat struct { + Name string +} + +func (c Cat) Name() string { return c.Name } +func (c Cat) Sound() string { return "喵喵" } +func (c Cat) Move() { fmt.Printf(" %s 在悄悄走路\n", c.Name) } + +// 鸟 +type Bird struct { + Name string +} + +func (b Bird) Name() string { return b.Name } +func (b Bird) Sound() string { return "啾啾" } +func (b Bird) Move() { fmt.Printf(" %s 在飞翔\n", b.Name) } + +// 信用卡 +type CreditCard struct { + CardNumber string + Balance float64 +} + +func (cc CreditCard) Pay(amount float64) bool { + if cc.Balance >= amount { + fmt.Printf(" 信用卡支付 $%.2f 成功\n", amount) + return true + } + return false +} + +func (cc CreditCard) GetName() string { + return "信用卡" +} + +// PayPal +type PayPal struct { + Email string + Balance float64 +} + +func (pp PayPal) Pay(amount float64) bool { + if pp.Balance >= amount { + fmt.Printf(" PayPal 支付 $%.2f 成功\n", amount) + return true + } + return false +} + +func (pp PayPal) GetName() string { + return "PayPal" +} + +// 现金 +type Cash struct { + Amount float64 +} + +func (c Cash) Pay(amount float64) bool { + if c.Amount >= amount { + fmt.Printf(" 现金支付 $%.2f 成功\n", amount) + return true + } + return false +} + +func (c Cash) GetName() string { + return "现金" +} + +// 整数切片排序 +type IntSlice []int + +func (is IntSlice) Len() int { return len(is) } +func (is IntSlice) Less(i, j int) bool { return is[i] < is[j] } +func (is IntSlice) Swap(i, j int) { is[i], is[j] = is[j], is[i] } + +// 字符串切片排序 +type StringSlice []string + +func (ss StringSlice) Len() int { return len(ss) } +func (ss StringSlice) Less(i, j int) bool { return ss[i] < ss[j] } +func (ss StringSlice) Swap(i, j int) { ss[i], ss[j] = ss[j], ss[i] } + +// 文件读写器 +type FileReadWriter struct { + filename string + content string +} + +func (frw *FileReadWriter) Read(data []byte) int { + n := copy(data, []byte(frw.content)) + fmt.Printf(" 从文件 %s 读取 %d 字节\n", frw.filename, n) + return n +} + +func (frw *FileReadWriter) Write(data []byte) int { + frw.content = string(data) + fmt.Printf(" 写入文件 %s: %s\n", frw.filename, string(data)) + return len(data) +} + +func (frw *FileReadWriter) Close() { + fmt.Printf(" 关闭文件 %s\n", frw.filename) +} + +// 视频播放器 +type VideoPlayer struct { + filename string + volume int + position int +} + +func (vp *VideoPlayer) Play() { + fmt.Printf(" 播放视频: %s\n", vp.filename) +} + +func (vp *VideoPlayer) Pause() { + fmt.Printf(" 暂停视频: %s\n", vp.filename) +} + +func (vp *VideoPlayer) Stop() { + fmt.Printf(" 停止视频: %s\n", vp.filename) +} + +func (vp *VideoPlayer) SetVolume(volume int) { + vp.volume = volume + fmt.Printf(" 设置音量: %d\n", volume) +} + +func (vp *VideoPlayer) Seek(position int) { + vp.position = position + fmt.Printf(" 跳转到位置: %d 秒\n", position) +} + +func (vp *VideoPlayer) SetBrightness(brightness int) { + fmt.Printf(" 设置亮度: %d\n", brightness) +} + +func (vp *VideoPlayer) SetContrast(contrast int) { + fmt.Printf(" 设置对比度: %d\n", contrast) +}// 开发者 +ty +pe Developer struct { + Name string + Language string + Experience int +} + +func (d Developer) GetName() string { return d.Name } +func (d Developer) GetRole() string { return "开发者" } +func (d Developer) GetSalary() float64 { return float64(d.Experience) * 10000 } +func (d Developer) Work() { fmt.Printf(" %s 正在用 %s 编程\n", d.Name, d.Language) } + +// 经理 +type Manager struct { + Name string + Department string + TeamSize int +} + +func (m Manager) GetName() string { return m.Name } +func (m Manager) GetRole() string { return "经理" } +func (m Manager) GetSalary() float64 { return float64(m.TeamSize) * 8000 } +func (m Manager) Work() { fmt.Printf(" %s 正在管理 %s 部门\n", m.Name, m.Department) } + +// 设计师 +type Designer struct { + Name string + Tool string + Portfolio []string +} + +func (d Designer) GetName() string { return d.Name } +func (d Designer) GetRole() string { return "设计师" } +func (d Designer) GetSalary() float64 { return float64(len(d.Portfolio)) * 12000 } +func (d Designer) Work() { fmt.Printf(" %s 正在用 %s 设计\n", d.Name, d.Tool) } + +// 通知系统 +type NotificationSystem struct { + providers []NotificationProvider +} + +func (ns *NotificationSystem) SendNotification(message string) { + for _, provider := range ns.providers { + provider.SendNotification(message) + } +} + +// 邮件提供者 +type EmailProvider struct { + SMTPServer string +} + +func (ep EmailProvider) SendNotification(message string) error { + fmt.Printf(" 通过邮件发送: %s\n", message) + return nil +} + +// 短信提供者 +type SMSProvider struct { + APIKey string +} + +func (sp SMSProvider) SendNotification(message string) error { + fmt.Printf(" 通过短信发送: %s\n", message) + return nil +} + +// 推送提供者 +type PushProvider struct { + AppID string +} + +func (pp PushProvider) SendNotification(message string) error { + fmt.Printf(" 通过推送发送: %s\n", message) + return nil +} + +// MySQL 数据库 +type MySQL struct{} + +func (m MySQL) Connect() error { + fmt.Printf(" 连接到 MySQL 数据库\n") + return nil +} + +func (m MySQL) Query(sql string) ([]map[string]interface{}, error) { + fmt.Printf(" 执行 MySQL 查询: %s\n", sql) + return nil, nil +} + +func (m MySQL) Close() error { + fmt.Printf(" 关闭 MySQL 连接\n") + return nil +} + +// PostgreSQL 数据库 +type PostgreSQL struct{} + +func (p PostgreSQL) Connect() error { + fmt.Printf(" 连接到 PostgreSQL 数据库\n") + return nil +} + +func (p PostgreSQL) Query(sql string) ([]map[string]interface{}, error) { + fmt.Printf(" 执行 PostgreSQL 查询: %s\n", sql) + return nil, nil +} + +func (p PostgreSQL) Close() error { + fmt.Printf(" 关闭 PostgreSQL 连接\n") + return nil +} + +// Redis 数据库 +type Redis struct{} + +func (r Redis) Connect() error { + fmt.Printf(" 连接到 Redis 数据库\n") + return nil +} + +func (r Redis) Query(cmd string) ([]map[string]interface{}, error) { + fmt.Printf(" 执行 Redis 命令: %s\n", cmd) + return nil, nil +} + +func (r Redis) Close() error { + fmt.Printf(" 关闭 Redis 连接\n") + return nil +} + +// Person 结构体 +type Person struct { + Name string + Age int +} + +func (p Person) String() string { + return fmt.Sprintf("Person(name=%s, age=%d)", p.Name, p.Age) +} + +// HTTP 服务器 +type HTTPServer struct { + port int + routes map[string]string +} + +func (hs *HTTPServer) Start() error { + fmt.Printf(" HTTP 服务器在端口 %d 启动\n", hs.port) + return nil +} + +func (hs *HTTPServer) Stop() error { + fmt.Printf(" HTTP 服务器停止\n") + return nil +} + +func (hs *HTTPServer) HandleRequest(path string) string { + if response, exists := hs.routes[path]; exists { + fmt.Printf(" 处理请求 %s: %s\n", path, response) + return response + } + fmt.Printf(" 404: 路径 %s 未找到\n", path) + return "404 Not Found" +} + +// 插件管理器 +type PluginManager struct { + plugins []Plugin +} + +func (pm *PluginManager) RegisterPlugin(plugin Plugin) { + pm.plugins = append(pm.plugins, plugin) + fmt.Printf(" 注册插件: %s\n", plugin.Name()) +} + +func (pm *PluginManager) ExecutePlugins(data interface{}) { + for _, plugin := range pm.plugins { + plugin.Execute(data) + } +} + +// 日志插件 +type LoggingPlugin struct{} + +func (lp *LoggingPlugin) Name() string { return "日志插件" } +func (lp *LoggingPlugin) Execute(data interface{}) error { + fmt.Printf(" [日志] %v\n", data) + return nil +} + +// 缓存插件 +type CachePlugin struct{} + +func (cp *CachePlugin) Name() string { return "缓存插件" } +func (cp *CachePlugin) Execute(data interface{}) error { + fmt.Printf(" [缓存] 缓存数据: %v\n", data) + return nil +} + +// 安全插件 +type SecurityPlugin struct{} + +func (sp *SecurityPlugin) Name() string { return "安全插件" } +func (sp *SecurityPlugin) Execute(data interface{}) error { + fmt.Printf(" [安全] 安全检查: %v\n", data) + return nil +} + +// 数据排序器 +type DataSorter struct { + data []int + strategy SortStrategy +} + +func (ds *DataSorter) SetStrategy(strategy SortStrategy) { + ds.strategy = strategy +} + +func (ds *DataSorter) Sort() { + if ds.strategy != nil { + ds.strategy.Sort(ds.data) + } +} + +// 冒泡排序 +type BubbleSort struct{} + +func (bs *BubbleSort) Sort(data []int) { + n := len(data) + for i := 0; i < n-1; i++ { + for j := 0; j < n-i-1; j++ { + if data[j] > data[j+1] { + data[j], data[j+1] = data[j+1], data[j] + } + } + } +} + +// 快速排序 +type QuickSort struct{} + +func (qs *QuickSort) Sort(data []int) { + qs.quickSort(data, 0, len(data)-1) +} + +func (qs *QuickSort) quickSort(data []int, low, high int) { + if low < high { + pi := qs.partition(data, low, high) + qs.quickSort(data, low, pi-1) + qs.quickSort(data, pi+1, high) + } +} + +func (qs *QuickSort) partition(data []int, low, high int) int { + pivot := data[high] + i := low - 1 + + for j := low; j < high; j++ { + if data[j] < pivot { + i++ + data[i], data[j] = data[j], data[i] + } + } + data[i+1], data[high] = data[high], data[i+1] + return i + 1 +} + +// 新闻机构 +type NewsAgency struct { + observers []Observer +} + +func (na *NewsAgency) Subscribe(observer Observer) { + na.observers = append(na.observers, observer) +} + +func (na *NewsAgency) Unsubscribe(observer Observer) { + for i, obs := range na.observers { + if obs == observer { + na.observers = append(na.observers[:i], na.observers[i+1:]...) + break + } + } +} + +func (na *NewsAgency) Notify(news string) { + for _, observer := range na.observers { + observer.Update(news) + } +} + +func (na *NewsAgency) PublishNews(news string) { + fmt.Printf(" 发布新闻: %s\n", news) + na.Notify(news) +} + +// 电视频道 +type TVChannel struct { + name string +} + +func (tv *TVChannel) Update(news string) { + fmt.Printf(" %s 播报: %s\n", tv.name, news) +} + +// 广播电台 +type RadioStation struct { + name string +} + +func (rs *RadioStation) Update(news string) { + fmt.Printf(" %s 播报: %s\n", rs.name, news) +} + +// 新闻网站 +type NewsWebsite struct { + name string +} + +func (nw *NewsWebsite) Update(news string) { + fmt.Printf(" %s 发布: %s\n", nw.name, news) +} + +// 文件日志记录器 +type FileLogger struct{} + +func (fl FileLogger) Log(message string) { + fmt.Printf(" [文件日志] %s\n", message) +} + +// 控制台日志记录器 +type ConsoleLogger struct{} + +func (cl ConsoleLogger) Log(message string) { + fmt.Printf(" [控制台日志] %s\n", message) +} + +// 数据库日志记录器 +type DatabaseLogger struct{} + +func (dl DatabaseLogger) Log(message string) { + fmt.Printf(" [数据库日志] %s\n", message) +} + +// 旧支付系统 +type OldPaymentSystem struct{} + +func (ops *OldPaymentSystem) MakePayment(amount float64) { + fmt.Printf(" 旧系统处理支付: $%.2f\n", amount) +} + +// 支付适配器 +type PaymentAdapter struct { + oldSystem *OldPaymentSystem +} + +func (pa *PaymentAdapter) ProcessPayment(amount float64, currency string) bool { + fmt.Printf(" 适配器转换: %.2f %s\n", amount, currency) + pa.oldSystem.MakePayment(amount) + return true +} + +// ========== 辅助函数 ========== + +// 排序函数 +func Sort(data Sortable) { + n := data.Len() + for i := 0; i < n-1; i++ { + for j := 0; j < n-i-1; j++ { + if data.Less(j+1, j) { + data.Swap(j, j+1) + } + } + } +} + +// 计算总面积 +func calculateTotalArea(shapes []Shape) float64 { + total := 0.0 + for _, shape := range shapes { + total += shape.Area() + } + return total +} + +// 找出最大面积的形状 +func findLargestShape(shapes []Shape) Shape { + if len(shapes) == 0 { + return nil + } + + largest := shapes[0] + maxArea := largest.Area() + + for _, shape := range shapes[1:] { + if area := shape.Area(); area > maxArea { + maxArea = area + largest = shape + } + } + + return largest +} + +// 数据库工厂函数 +func createDatabase(dbType string) Database { + switch dbType { + case "mysql": + return MySQL{} + case "postgres": + return PostgreSQL{} + case "redis": + return Redis{} + default: + return MySQL{} + } +} + +// 日志记录器工厂函数 +func CreateLogger(loggerType string) Logger { + switch loggerType { + case "file": + return FileLogger{} + case "console": + return ConsoleLogger{} + case "database": + return DatabaseLogger{} + default: + return ConsoleLogger{} + } +} + +/* +运行这个程序: +go run 01-basic-interfaces.go + +学习要点: +1. 接口定义了方法签名的集合,是一种抽象类型 +2. Go 语言的接口实现是隐式的,无需显式声明 +3. 接口支持多态,允许不同类型以统一方式处理 +4. 接口可以组合,通过嵌入其他接口实现 +5. 接口是 Go 语言实现抽象和多态的核心机制 + +接口的特性: +1. 隐式实现:只要实现了接口的所有方法就自动实现了接口 +2. 多态性:不同类型可以实现同一接口 +3. 组合性:接口可以嵌入其他接口 +4. 类型安全:编译时检查接口实现 +5. 零值:接口的零值是 nil + +接口的优势: +1. 代码解耦:依赖抽象而不是具体实现 +2. 可测试性:便于编写单元测试和模拟对象 +3. 可扩展性:新类型可以轻松实现现有接口 +4. 多态性:统一处理不同类型的对象 +5. 组合性:通过接口组合实现复杂功能 + +接口设计原则: +1. 接口应该小而专注(单一职责) +2. 优先定义行为而不是数据 +3. 接口名通常以 -er 结尾 +4. 避免过度抽象 +5. 考虑接口的可组合性 + +常见应用场景: +1. 多态处理:统一处理不同类型 +2. 依赖注入:解耦具体实现 +3. 插件系统:动态加载和执行 +4. 策略模式:算法的动态选择 +5. 观察者模式:事件通知机制 +6. 适配器模式:接口适配 +7. 工厂模式:对象创建抽象 + +最佳实践: +1. 保持接口简单和专注 +2. 优先使用小接口而不是大接口 +3. 在需要的地方定义接口 +4. 使用接口实现依赖倒置 +5. 合理使用接口组合 +6. 避免不必要的接口抽象 + +注意事项: +1. nil 接口不能调用方法 +2. 接口类型断言需要检查成功与否 +3. 接口实现是编译时检查的 +4. 空接口可以持有任何类型的值 +5. 接口比较需要注意动态类型和动态值 +*/ \ No newline at end of file diff --git a/golang-learning/05-interfaces/02-empty-interface.go b/golang-learning/05-interfaces/02-empty-interface.go new file mode 100644 index 0000000..3fe5c21 --- /dev/null +++ b/golang-learning/05-interfaces/02-empty-interface.go @@ -0,0 +1,981 @@ +/* +02-empty-interface.go - Go 语言空接口详解 + +学习目标: +1. 理解空接口的概念和特性 +2. 掌握空接口的使用场景 +3. 学会空接口的类型断言 +4. 了解空接口的性能考虑 +5. 掌握空接口的实际应用 + +知识点: +- 空接口的定义 interface{} +- 空接口可以持有任何类型的值 +- 空接口的类型断言和类型判断 +- 空接口在泛型编程中的应用 +- 空接口的性能影响 +- 空接口的最佳实践 +*/ + +package main + +import ( + "fmt" + "reflect" + "strconv" +) + +func main() { + fmt.Println("=== Go 语言空接口详解 ===\n") + + // 演示空接口的基本概念 + demonstrateBasicEmptyInterface() + + // 演示空接口的类型断言 + demonstrateTypeAssertion() + + // 演示空接口的类型判断 + demonstrateTypeSwitch() + + // 演示空接口的实际应用 + demonstratePracticalUsage() + + // 演示空接口的高级用法 + demonstrateAdvancedUsage() + + // 演示空接口的性能考虑 + demonstratePerformanceConsiderations() + + // 演示空接口的最佳实践 + demonstrateBestPractices() +} + +// demonstrateBasicEmptyInterface 演示空接口的基本概念 +func demonstrateBasicEmptyInterface() { + fmt.Println("1. 空接口的基本概念:") + + // 空接口的基本特性 + fmt.Printf(" 空接口的基本特性:\n") + fmt.Printf(" - interface{} 不包含任何方法\n") + fmt.Printf(" - 可以持有任何类型的值\n") + fmt.Printf(" - 相当于其他语言中的 Object 或 Any\n") + fmt.Printf(" - 零值是 nil\n") + fmt.Printf(" - 运行时类型信息保存在接口中\n") + + // 基本空接口示例 + fmt.Printf(" 基本空接口示例:\n") + + var empty interface{} + fmt.Printf(" 空接口零值: %v\n", empty) + fmt.Printf(" 空接口 == nil: %t\n", empty == nil) + + // 存储不同类型的值 + empty = 42 + fmt.Printf(" 存储整数: %v (类型: %T)\n", empty, empty) + + empty = "Hello, World!" + fmt.Printf(" 存储字符串: %v (类型: %T)\n", empty, empty) + + empty = 3.14159 + fmt.Printf(" 存储浮点数: %v (类型: %T)\n", empty, empty) + + empty = true + fmt.Printf(" 存储布尔值: %v (类型: %T)\n", empty, empty) + + empty = []int{1, 2, 3, 4, 5} + fmt.Printf(" 存储切片: %v (类型: %T)\n", empty, empty) + + empty = map[string]int{"a": 1, "b": 2} + fmt.Printf(" 存储映射: %v (类型: %T)\n", empty, empty) + + // 存储结构体 + type Person struct { + Name string + Age int + } + + empty = Person{Name: "Alice", Age: 30} + fmt.Printf(" 存储结构体: %v (类型: %T)\n", empty, empty) + + // 存储指针 + person := &Person{Name: "Bob", Age: 25} + empty = person + fmt.Printf(" 存储指针: %v (类型: %T)\n", empty, empty) + + // 存储函数 + empty = func(x int) int { return x * 2 } + fmt.Printf(" 存储函数: %v (类型: %T)\n", empty, empty) + + fmt.Println() +} + +// demonstrateTypeAssertion 演示空接口的类型断言 +func demonstrateTypeAssertion() { + fmt.Println("2. 空接口的类型断言:") + + fmt.Printf(" 类型断言用于从接口中提取具体类型的值\n") + + // 基本类型断言 + fmt.Printf(" 基本类型断言:\n") + + var value interface{} = "Hello, Go!" + + // 安全的类型断言 + if str, ok := value.(string); ok { + fmt.Printf(" 类型断言成功: %s (长度: %d)\n", str, len(str)) + } else { + fmt.Printf(" 类型断言失败\n") + } + + // 不安全的类型断言(可能 panic) + str := value.(string) + fmt.Printf(" 直接类型断言: %s\n", str) + + // 类型断言失败的情况 + fmt.Printf(" 类型断言失败的情况:\n") + + value = 42 + if str, ok := value.(string); ok { + fmt.Printf(" 字符串断言成功: %s\n", str) + } else { + fmt.Printf(" 字符串断言失败,实际类型: %T\n", value) + } + + // 断言为整数 + if num, ok := value.(int); ok { + fmt.Printf(" 整数断言成功: %d\n", num) + } + + // 多种类型断言 + fmt.Printf(" 多种类型断言:\n") + + values := []interface{}{ + 42, + "Hello", + 3.14, + true, + []int{1, 2, 3}, + map[string]int{"key": 100}, + } + + for i, v := range values { + fmt.Printf(" 值 %d (%v):\n", i+1, v) + + // 尝试不同的类型断言 + if intVal, ok := v.(int); ok { + fmt.Printf(" 整数: %d\n", intVal) + } else if strVal, ok := v.(string); ok { + fmt.Printf(" 字符串: %s\n", strVal) + } else if floatVal, ok := v.(float64); ok { + fmt.Printf(" 浮点数: %.2f\n", floatVal) + } else if boolVal, ok := v.(bool); ok { + fmt.Printf(" 布尔值: %t\n", boolVal) + } else { + fmt.Printf(" 其他类型: %T\n", v) + } + } + + fmt.Println() +} + +// demonstrateTypeSwitch 演示空接口的类型判断 +func demonstrateTypeSwitch() { + fmt.Println("3. 空接口的类型判断:") + + fmt.Printf(" 类型 switch 是处理空接口的优雅方式\n") + + // 基本类型 switch + fmt.Printf(" 基本类型 switch:\n") + + values := []interface{}{ + 42, + "Hello, World!", + 3.14159, + true, + []int{1, 2, 3, 4, 5}, + map[string]int{"a": 1, "b": 2}, + nil, + struct{ Name string }{"Alice"}, + } + + for i, value := range values { + fmt.Printf(" 值 %d: ", i+1) + processValue(value) + } + + // 复杂类型 switch + fmt.Printf(" 复杂类型 switch:\n") + + complexValues := []interface{}{ + Person{Name: "Alice", Age: 30}, + &Person{Name: "Bob", Age: 25}, + Employee{Person: Person{Name: "Charlie", Age: 35}, Position: "Developer"}, + []Person{{Name: "David", Age: 28}}, + make(chan int), + func() { fmt.Println("函数") }, + } + + for i, value := range complexValues { + fmt.Printf(" 复杂值 %d: ", i+1) + processComplexValue(value) + } + + // 类型 switch 的实际应用 + fmt.Printf(" 类型 switch 的实际应用:\n") + + // JSON 解析模拟 + jsonData := map[string]interface{}{ + "name": "Alice", + "age": 30, + "salary": 75000.50, + "active": true, + "skills": []interface{}{"Go", "Python", "JavaScript"}, + "address": map[string]interface{}{ + "city": "New York", + "zipcode": "10001", + }, + } + + fmt.Printf(" JSON 数据处理:\n") + processJSONData(jsonData, "") + + fmt.Println() +} + +// demonstratePracticalUsage 演示空接口的实际应用 +func demonstratePracticalUsage() { + fmt.Println("4. 空接口的实际应用:") + + // 应用1: 通用容器 + fmt.Printf(" 应用1 - 通用容器:\n") + + container := NewContainer() + + // 存储不同类型的数据 + container.Add("字符串数据") + container.Add(42) + container.Add(3.14) + container.Add([]int{1, 2, 3}) + + fmt.Printf(" 容器大小: %d\n", container.Size()) + fmt.Printf(" 容器内容:\n") + for i := 0; i < container.Size(); i++ { + item := container.Get(i) + fmt.Printf(" [%d]: %v (%T)\n", i, item, item) + } + + // 应用2: 配置系统 + fmt.Printf(" 应用2 - 配置系统:\n") + + config := NewConfig() + + // 设置不同类型的配置 + config.Set("app_name", "MyApp") + config.Set("port", 8080) + config.Set("debug", true) + config.Set("timeout", 30.5) + config.Set("features", []string{"auth", "logging", "metrics"}) + + // 获取配置 + fmt.Printf(" 应用名称: %v\n", config.Get("app_name")) + fmt.Printf(" 端口: %v\n", config.Get("port")) + fmt.Printf(" 调试模式: %v\n", config.Get("debug")) + fmt.Printf(" 超时时间: %v\n", config.Get("timeout")) + fmt.Printf(" 功能列表: %v\n", config.Get("features")) + + // 类型安全的获取 + if port, ok := config.GetInt("port"); ok { + fmt.Printf(" 端口 (类型安全): %d\n", port) + } + + if debug, ok := config.GetBool("debug"); ok { + fmt.Printf(" 调试模式 (类型安全): %t\n", debug) + } + + // 应用3: 事件系统 + fmt.Printf(" 应用3 - 事件系统:\n") + + eventBus := NewEventBus() + + // 注册事件处理器 + eventBus.Subscribe("user_login", func(data interface{}) { + if user, ok := data.(map[string]interface{}); ok { + fmt.Printf(" 用户登录: %s\n", user["username"]) + } + }) + + eventBus.Subscribe("order_created", func(data interface{}) { + if order, ok := data.(map[string]interface{}); ok { + fmt.Printf(" 订单创建: ID=%v, 金额=$%.2f\n", + order["id"], order["amount"]) + } + }) + + // 发布事件 + eventBus.Publish("user_login", map[string]interface{}{ + "username": "alice", + "ip": "192.168.1.100", + }) + + eventBus.Publish("order_created", map[string]interface{}{ + "id": 12345, + "amount": 99.99, + "items": []string{"laptop", "mouse"}, + }) + + // 应用4: 数据转换 + fmt.Printf(" 应用4 - 数据转换:\n") + + converter := DataConverter{} + + // 转换不同类型的数据 + testData := []interface{}{ + 42, + "123", + 3.14, + true, + "false", + []int{1, 2, 3}, + } + + for _, data := range testData { + result := converter.ToString(data) + fmt.Printf(" %v (%T) -> \"%s\"\n", data, data, result) + } + + fmt.Println() +} + +// demonstrateAdvancedUsage 演示空接口的高级用法 +func demonstrateAdvancedUsage() { + fmt.Println("5. 空接口的高级用法:") + + // 高级用法1: 反射结合空接口 + fmt.Printf(" 高级用法1 - 反射结合空接口:\n") + + inspector := TypeInspector{} + + values := []interface{}{ + 42, + "Hello", + []int{1, 2, 3}, + map[string]int{"a": 1}, + Person{Name: "Alice", Age: 30}, + &Person{Name: "Bob", Age: 25}, + } + + for _, value := range values { + inspector.Inspect(value) + } + + // 高级用法2: 深拷贝 + fmt.Printf(" 高级用法2 - 深拷贝:\n") + + original := map[string]interface{}{ + "name": "Alice", + "age": 30, + "address": map[string]interface{}{ + "city": "New York", + "zip": "10001", + }, + "hobbies": []interface{}{"reading", "swimming"}, + } + + copied := deepCopy(original) + + fmt.Printf(" 原始数据: %v\n", original) + fmt.Printf(" 拷贝数据: %v\n", copied) + + // 修改拷贝数据 + if copiedMap, ok := copied.(map[string]interface{}); ok { + copiedMap["name"] = "Bob" + if address, ok := copiedMap["address"].(map[string]interface{}); ok { + address["city"] = "Boston" + } + } + + fmt.Printf(" 修改后原始: %v\n", original) + fmt.Printf(" 修改后拷贝: %v\n", copied) + + // 高级用法3: 序列化和反序列化 + fmt.Printf(" 高级用法3 - 序列化和反序列化:\n") + + serializer := SimpleSerializer{} + + data := map[string]interface{}{ + "user_id": 123, + "name": "Alice", + "active": true, + "score": 95.5, + } + + // 序列化 + serialized := serializer.Serialize(data) + fmt.Printf(" 序列化结果: %s\n", serialized) + + // 反序列化 + deserialized := serializer.Deserialize(serialized) + fmt.Printf(" 反序列化结果: %v\n", deserialized) + + fmt.Println() +} + +// demonstratePerformanceConsiderations 演示空接口的性能考虑 +func demonstratePerformanceConsiderations() { + fmt.Println("6. 空接口的性能考虑:") + + fmt.Printf(" 空接口的性能影响:\n") + fmt.Printf(" - 类型信息存储开销\n") + fmt.Printf(" - 装箱和拆箱成本\n") + fmt.Printf(" - 类型断言的运行时检查\n") + fmt.Printf(" - 垃圾回收压力增加\n") + + // 性能对比示例 + fmt.Printf(" 性能对比示例:\n") + + // 直接类型操作 + var directSum int + for i := 0; i < 1000; i++ { + directSum += i + } + fmt.Printf(" 直接类型操作结果: %d\n", directSum) + + // 空接口操作 + var interfaceSum int + var values []interface{} + for i := 0; i < 1000; i++ { + values = append(values, i) + } + + for _, v := range values { + if num, ok := v.(int); ok { + interfaceSum += num + } + } + fmt.Printf(" 空接口操作结果: %d\n", interfaceSum) + + // 内存使用对比 + fmt.Printf(" 内存使用对比:\n") + + // 直接存储 + directSlice := make([]int, 1000) + for i := range directSlice { + directSlice[i] = i + } + + // 接口存储 + interfaceSlice := make([]interface{}, 1000) + for i := range interfaceSlice { + interfaceSlice[i] = i + } + + fmt.Printf(" 直接存储切片长度: %d\n", len(directSlice)) + fmt.Printf(" 接口存储切片长度: %d\n", len(interfaceSlice)) + fmt.Printf(" 注意: 接口存储会有额外的内存开销\n") + + fmt.Println() +} + +// demonstrateBestPractices 演示空接口的最佳实践 +func demonstrateBestPractices() { + fmt.Println("7. 空接口的最佳实践:") + + fmt.Printf(" 最佳实践原则:\n") + fmt.Printf(" 1. 避免过度使用空接口\n") + fmt.Printf(" 2. 优先使用具体类型或定义的接口\n") + fmt.Printf(" 3. 使用类型断言时要检查成功与否\n") + fmt.Printf(" 4. 考虑使用泛型替代空接口(Go 1.18+)\n") + fmt.Printf(" 5. 在 API 边界谨慎使用空接口\n") + + // 好的实践示例 + fmt.Printf(" 好的实践示例:\n") + + // 1. 明确的接口定义 + fmt.Printf(" 1. 使用明确的接口而不是空接口:\n") + + var printer Printer = ConsolePrinter{} + printer.Print("使用明确接口的消息") + + // 2. 类型安全的容器 + fmt.Printf(" 2. 类型安全的容器:\n") + + stringContainer := NewTypedContainer[string]() + stringContainer.Add("Hello") + stringContainer.Add("World") + + fmt.Printf(" 字符串容器: %v\n", stringContainer.GetAll()) + + intContainer := NewTypedContainer[int]() + intContainer.Add(1) + intContainer.Add(2) + intContainer.Add(3) + + fmt.Printf(" 整数容器: %v\n", intContainer.GetAll()) + + // 3. 错误处理 + fmt.Printf(" 3. 正确的错误处理:\n") + + result, err := safeTypeAssertion("Hello, World!", "string") + if err != nil { + fmt.Printf(" 类型断言错误: %v\n", err) + } else { + fmt.Printf(" 类型断言成功: %v\n", result) + } + + result, err = safeTypeAssertion(42, "string") + if err != nil { + fmt.Printf(" 类型断言错误: %v\n", err) + } else { + fmt.Printf(" 类型断言成功: %v\n", result) + } + + // 避免的反模式 + fmt.Printf(" 避免的反模式:\n") + fmt.Printf(" - 函数参数和返回值过度使用 interface{}\n") + fmt.Printf(" - 不检查类型断言的成功与否\n") + fmt.Printf(" - 在性能敏感的代码中大量使用空接口\n") + fmt.Printf(" - 用空接口替代适当的类型设计\n") + + fmt.Println() +} + +// ========== 类型定义 ========== + +// 基本结构体 +type Person struct { + Name string + Age int +} + +type Employee struct { + Person + Position string +} + +// 打印器接口 +type Printer interface { + Print(message string) +} + +type ConsolePrinter struct{} + +func (cp ConsolePrinter) Print(message string) { + fmt.Printf(" [控制台] %s\n", message) +} + +// ========== 实用工具类型 ========== + +// 通用容器 +type Container struct { + items []interface{} +} + +func NewContainer() *Container { + return &Container{items: make([]interface{}, 0)} +} + +func (c *Container) Add(item interface{}) { + c.items = append(c.items, item) +} + +func (c *Container) Get(index int) interface{} { + if index >= 0 && index < len(c.items) { + return c.items[index] + } + return nil +} + +func (c *Container) Size() int { + return len(c.items) +} + +// 配置系统 +type Config struct { + data map[string]interface{} +} + +func NewConfig() *Config { + return &Config{data: make(map[string]interface{})} +} + +func (c *Config) Set(key string, value interface{}) { + c.data[key] = value +} + +func (c *Config) Get(key string) interface{} { + return c.data[key] +} + +func (c *Config) GetString(key string) (string, bool) { + if value, exists := c.data[key]; exists { + if str, ok := value.(string); ok { + return str, true + } + } + return "", false +} + +func (c *Config) GetInt(key string) (int, bool) { + if value, exists := c.data[key]; exists { + if num, ok := value.(int); ok { + return num, true + } + } + return 0, false +} + +func (c *Config) GetBool(key string) (bool, bool) { + if value, exists := c.data[key]; exists { + if b, ok := value.(bool); ok { + return b, true + } + } + return false, false +} + +// 事件系统 +type EventBus struct { + handlers map[string][]func(interface{}) +} + +func NewEventBus() *EventBus { + return &EventBus{handlers: make(map[string][]func(interface{}))} +} + +func (eb *EventBus) Subscribe(event string, handler func(interface{})) { + eb.handlers[event] = append(eb.handlers[event], handler) +} + +func (eb *EventBus) Publish(event string, data interface{}) { + if handlers, exists := eb.handlers[event]; exists { + for _, handler := range handlers { + handler(data) + } + } +} + +// 数据转换器 +type DataConverter struct{} + +func (dc DataConverter) ToString(value interface{}) string { + switch v := value.(type) { + case string: + return v + case int: + return strconv.Itoa(v) + case float64: + return strconv.FormatFloat(v, 'f', -1, 64) + case bool: + return strconv.FormatBool(v) + case []int: + result := "[" + for i, num := range v { + if i > 0 { + result += ", " + } + result += strconv.Itoa(num) + } + result += "]" + return result + default: + return fmt.Sprintf("%v", v) + } +} + +// 类型检查器 +type TypeInspector struct{} + +func (ti TypeInspector) Inspect(value interface{}) { + if value == nil { + fmt.Printf(" nil 值\n") + return + } + + t := reflect.TypeOf(value) + v := reflect.ValueOf(value) + + fmt.Printf(" 类型: %s, 种类: %s, 值: %v\n", t.String(), t.Kind().String(), value) + + switch t.Kind() { + case reflect.Struct: + fmt.Printf(" 结构体字段数: %d\n", t.NumField()) + for i := 0; i < t.NumField(); i++ { + field := t.Field(i) + fieldValue := v.Field(i) + fmt.Printf(" %s: %v (%s)\n", field.Name, fieldValue.Interface(), field.Type) + } + case reflect.Ptr: + fmt.Printf(" 指针指向: %s\n", t.Elem().String()) + if !v.IsNil() { + fmt.Printf(" 指针值: %v\n", v.Elem().Interface()) + } + case reflect.Slice: + fmt.Printf(" 切片长度: %d, 容量: %d\n", v.Len(), v.Cap()) + fmt.Printf(" 元素类型: %s\n", t.Elem().String()) + case reflect.Map: + fmt.Printf(" 映射长度: %d\n", v.Len()) + fmt.Printf(" 键类型: %s, 值类型: %s\n", t.Key().String(), t.Elem().String()) + } +} + +// 简单序列化器 +type SimpleSerializer struct{} + +func (ss SimpleSerializer) Serialize(data interface{}) string { + switch v := data.(type) { + case map[string]interface{}: + result := "{" + first := true + for key, value := range v { + if !first { + result += ", " + } + result += fmt.Sprintf("\"%s\": %s", key, ss.serializeValue(value)) + first = false + } + result += "}" + return result + default: + return ss.serializeValue(data) + } +} + +func (ss SimpleSerializer) serializeValue(value interface{}) string { + switch v := value.(type) { + case string: + return fmt.Sprintf("\"%s\"", v) + case int: + return strconv.Itoa(v) + case float64: + return strconv.FormatFloat(v, 'f', -1, 64) + case bool: + return strconv.FormatBool(v) + default: + return fmt.Sprintf("\"%v\"", v) + } +} + +func (ss SimpleSerializer) Deserialize(data string) interface{} { + // 简化的反序列化,实际应用中应该使用 JSON 包 + if data == "true" { + return true + } + if data == "false" { + return false + } + if num, err := strconv.Atoi(data); err == nil { + return num + } + if num, err := strconv.ParseFloat(data, 64); err == nil { + return num + } + return data +} + +// 类型安全的泛型容器(Go 1.18+) +type TypedContainer[T any] struct { + items []T +} + +func NewTypedContainer[T any]() *TypedContainer[T] { + return &TypedContainer[T]{items: make([]T, 0)} +} + +func (tc *TypedContainer[T]) Add(item T) { + tc.items = append(tc.items, item) +} + +func (tc *TypedContainer[T]) Get(index int) T { + var zero T + if index >= 0 && index < len(tc.items) { + return tc.items[index] + } + return zero +} + +func (tc *TypedContainer[T]) GetAll() []T { + return tc.items +} + +// ========== 辅助函数 ========== + +// 处理值的类型 switch +func processValue(value interface{}) { + switch v := value.(type) { + case nil: + fmt.Printf("nil 值\n") + case int: + fmt.Printf("整数: %d\n", v) + case string: + fmt.Printf("字符串: \"%s\" (长度: %d)\n", v, len(v)) + case float64: + fmt.Printf("浮点数: %.3f\n", v) + case bool: + fmt.Printf("布尔值: %t\n", v) + case []int: + fmt.Printf("整数切片: %v (长度: %d)\n", v, len(v)) + case map[string]int: + fmt.Printf("字符串到整数的映射: %v (大小: %d)\n", v, len(v)) + default: + fmt.Printf("未知类型: %T, 值: %v\n", v, v) + } +} + +// 处理复杂值的类型 switch +func processComplexValue(value interface{}) { + switch v := value.(type) { + case Person: + fmt.Printf("Person 结构体: %s (%d岁)\n", v.Name, v.Age) + case *Person: + fmt.Printf("Person 指针: %s (%d岁)\n", v.Name, v.Age) + case Employee: + fmt.Printf("Employee 结构体: %s - %s\n", v.Name, v.Position) + case []Person: + fmt.Printf("Person 切片: %d 个人\n", len(v)) + case chan int: + fmt.Printf("整数通道\n") + case func(): + fmt.Printf("无参数函数\n") + default: + fmt.Printf("其他复杂类型: %T\n", v) + } +} + +// 处理 JSON 数据 +func processJSONData(data map[string]interface{}, indent string) { + for key, value := range data { + fmt.Printf("%s %s: ", indent, key) + + switch v := value.(type) { + case string: + fmt.Printf("\"%s\" (字符串)\n", v) + case float64: + fmt.Printf("%.2f (数字)\n", v) + case bool: + fmt.Printf("%t (布尔值)\n", v) + case []interface{}: + fmt.Printf("数组 [%d 个元素]\n", len(v)) + for i, item := range v { + fmt.Printf("%s [%d]: %v (%T)\n", indent, i, item, item) + } + case map[string]interface{}: + fmt.Printf("对象 {%d 个字段}\n", len(v)) + processJSONData(v, indent+" ") + default: + fmt.Printf("%v (%T)\n", v, v) + } + } +} + +// 深拷贝函数 +func deepCopy(original interface{}) interface{} { + switch v := original.(type) { + case map[string]interface{}: + copied := make(map[string]interface{}) + for key, value := range v { + copied[key] = deepCopy(value) + } + return copied + case []interface{}: + copied := make([]interface{}, len(v)) + for i, value := range v { + copied[i] = deepCopy(value) + } + return copied + default: + // 基本类型直接返回(值拷贝) + return v + } +} + +// 安全的类型断言 +func safeTypeAssertion(value interface{}, expectedType string) (interface{}, error) { + switch expectedType { + case "string": + if str, ok := value.(string); ok { + return str, nil + } + return nil, fmt.Errorf("期望 string 类型,实际是 %T", value) + case "int": + if num, ok := value.(int); ok { + return num, nil + } + return nil, fmt.Errorf("期望 int 类型,实际是 %T", value) + case "bool": + if b, ok := value.(bool); ok { + return b, nil + } + return nil, fmt.Errorf("期望 bool 类型,实际是 %T", value) + default: + return nil, fmt.Errorf("不支持的类型: %s", expectedType) + } +} + +/* +运行这个程序: +go run 02-empty-interface.go + +学习要点: +1. 空接口 interface{} 可以持有任何类型的值 +2. 空接口是 Go 语言中最通用的类型 +3. 使用类型断言从空接口中提取具体类型的值 +4. 类型 switch 是处理空接口的优雅方式 +5. 空接口在泛型编程和动态类型处理中很有用 + +空接口的特性: +1. 通用性:可以存储任何类型的值 +2. 类型安全:通过类型断言保证类型安全 +3. 运行时类型信息:保存值的动态类型信息 +4. 零值:空接口的零值是 nil +5. 性能开销:有装箱拆箱的成本 + +类型断言: +1. 安全断言:value.(Type) 返回值和布尔标志 +2. 不安全断言:value.(Type) 只返回值,失败时 panic +3. 类型 switch:switch value.(type) 处理多种类型 +4. 类型检查:使用 ok 模式检查断言是否成功 + +常见应用场景: +1. 通用容器和集合 +2. 配置系统和参数传递 +3. JSON 和其他格式的数据处理 +4. 事件系统和消息传递 +5. 插件系统和动态加载 +6. 序列化和反序列化 +7. 反射和元编程 + +性能考虑: +1. 装箱开销:基本类型存储到接口需要装箱 +2. 类型断言成本:运行时类型检查有开销 +3. 内存使用:接口存储需要额外的类型信息 +4. 垃圾回收:可能增加 GC 压力 + +最佳实践: +1. 避免过度使用空接口 +2. 优先使用具体类型或定义的接口 +3. 使用类型断言时检查成功与否 +4. 考虑使用泛型替代空接口(Go 1.18+) +5. 在 API 设计中谨慎使用空接口 +6. 提供类型安全的包装函数 + +何时使用空接口: +1. 需要存储不同类型的值 +2. 处理动态类型的数据(如 JSON) +3. 实现通用的算法或容器 +4. 与反射结合使用 +5. 临时的类型转换需求 + +何时避免空接口: +1. 类型在编译时已知 +2. 性能敏感的代码 +3. 可以用泛型替代的场景 +4. API 的公共接口设计 +5. 简单的数据传递 + +注意事项: +1. nil 接口不能调用方法 +2. 类型断言失败可能导致 panic +3. 空接口比较需要注意动态类型 +4. 过度使用会降低代码的类型安全性 +5. 调试时类型信息可能不够清晰 +*/ \ No newline at end of file diff --git a/golang-learning/05-interfaces/03-type-assertions.go b/golang-learning/05-interfaces/03-type-assertions.go new file mode 100644 index 0000000..8a78bd8 --- /dev/null +++ b/golang-learning/05-interfaces/03-type-assertions.go @@ -0,0 +1,1058 @@ +/* +03-type-assertions.go - Go 语言类型断言详解 + +学习目标: +1. 掌握类型断言的语法和用法 +2. 理解类型断言的安全性 +3. 学会类型 switch 的使用 +4. 了解接口类型断言的应用 +5. 掌握类型断言的最佳实践 + +知识点: +- 类型断言的基本语法 +- 安全类型断言 vs 不安全类型断言 +- 类型 switch 语句 +- 接口到具体类型的断言 +- 接口到接口的断言 +- 类型断言的性能考虑 +- 类型断言的实际应用场景 +*/ + +package main + +import ( + "fmt" + "io" + "strings" +) + +func main() { + fmt.Println("=== Go 语言类型断言详解 ===\\n") + + // 演示基本类型断言 + demonstrateBasicTypeAssertions() + + // 演示安全 vs 不安全类型断言 + demonstrateSafeVsUnsafeAssertions() + + // 演示类型 switch + demonstrateTypeSwitchExamples() + + // 演示接口类型断言 + demonstrateInterfaceAssertions() + + // 演示类型断言的实际应用 + demonstratePracticalApplications() + + // 演示类型断言的高级用法 + demonstrateAdvancedUsageExamples() + + // 演示类型断言的最佳实践 + demonstrateBestPracticesExamples() +} + +// demonstrateBasicTypeAssertions 演示基本类型断言 +func demonstrateBasicTypeAssertions() { + fmt.Println("1. 基本类型断言:") + + // 类型断言的基本语法 + fmt.Printf(" 类型断言的基本语法:\\n") + fmt.Printf(" value.(Type) - 不安全断言,失败时 panic\\n") + fmt.Printf(" value, ok := value.(Type) - 安全断言,返回值和布尔标志\\n") + + // 基本类型断言示例 + fmt.Printf(" 基本类型断言示例:\\n") + + var value interface{} = "Hello, World!" + + // 安全的类型断言 + if str, ok := value.(string); ok { + fmt.Printf(" 字符串断言成功: \\\"%s\\\" (长度: %d)\\n", str, len(str)) + } else { + fmt.Printf(" 字符串断言失败\\n") + } + + // 断言为整数(会失败) + if num, ok := value.(int); ok { + fmt.Printf(" 整数断言成功: %d\\n", num) + } else { + fmt.Printf(" 整数断言失败,实际类型: %T\\n", value) + } + + // 不同类型的断言 + fmt.Printf(" 不同类型的断言:\\n") + + values := []interface{}{ + 42, + 3.14159, + true, + "Go语言", + []int{1, 2, 3}, + map[string]int{"key": 100}, + Person{Name: "Alice", Age: 30}, + } + + for i, v := range values { + fmt.Printf(" 值 %d (%v):\\n", i+1, v) + + // 尝试断言为不同类型 + if intVal, ok := v.(int); ok { + fmt.Printf(" -> 整数: %d\\n", intVal) + } else if floatVal, ok := v.(float64); ok { + fmt.Printf(" -> 浮点数: %.3f\\n", floatVal) + } else if boolVal, ok := v.(bool); ok { + fmt.Printf(" -> 布尔值: %t\\n", boolVal) + } else if strVal, ok := v.(string); ok { + fmt.Printf(" -> 字符串: \\\"%s\\\"\\n", strVal) + } else { + fmt.Printf(" -> 其他类型: %T\\n", v) + } + } + + fmt.Println() +} + +// demonstrateSafeVsUnsafeAssertions 演示安全 vs 不安全类型断言 +func demonstrateSafeVsUnsafeAssertions() { + fmt.Println("2. 安全 vs 不安全类型断言:") + + // 安全类型断言 + fmt.Printf(" 安全类型断言 (推荐):\\n") + + var value interface{} = 42 + + // 安全断言 - 返回值和布尔标志 + if str, ok := value.(string); ok { + fmt.Printf(" 字符串断言成功: %s\\n", str) + } else { + fmt.Printf(" 字符串断言失败,实际类型: %T,值: %v\\n", value, value) + } + + if num, ok := value.(int); ok { + fmt.Printf(" 整数断言成功: %d\\n", num) + } else { + fmt.Printf(" 整数断言失败\\n") + } + + // 不安全类型断言 + fmt.Printf(" 不安全类型断言 (谨慎使用):\\n") + + // 成功的不安全断言 + num := value.(int) + fmt.Printf(" 不安全整数断言成功: %d\\n", num) + + // 失败的不安全断言(会 panic) + fmt.Printf(" 演示不安全断言的 panic 风险:\\n") + + // 使用 defer 和 recover 捕获 panic + func() { + defer func() { + if r := recover(); r != nil { + fmt.Printf(" 捕获到 panic: %v\\n", r) + } + }() + + // 这会导致 panic + str := value.(string) + fmt.Printf(" 不安全字符串断言: %s\\n", str) + }() + + // 安全断言的实际应用 + fmt.Printf(" 安全断言的实际应用:\\n") + + data := []interface{}{ + "hello", + 42, + 3.14, + true, + nil, + } + + for i, item := range data { + fmt.Printf(" 处理项目 %d:\\n", i+1) + processItemSafely(item) + } + + fmt.Println() +} + +// demonstrateTypeSwitchExamples 演示类型 switch +func demonstrateTypeSwitchExamples() { + fmt.Println("3. 类型 switch:") + + fmt.Printf(" 类型 switch 是处理多种类型的优雅方式\\n") + + // 基本类型 switch + fmt.Printf(" 基本类型 switch:\\n") + + values := []interface{}{ + 42, + "Hello", + 3.14159, + true, + []int{1, 2, 3}, + map[string]int{"a": 1, "b": 2}, + Person{Name: "Alice", Age: 30}, + &Person{Name: "Bob", Age: 25}, + nil, + } + + for i, value := range values { + fmt.Printf(" 值 %d: ", i+1) + processWithTypeSwitch(value) + } + + // 类型 switch 的高级用法 + fmt.Printf(" 类型 switch 的高级用法:\\n") + + // 处理不同的数值类型 + numbers := []interface{}{ + int(42), + int8(8), + int16(16), + int32(32), + int64(64), + uint(42), + float32(3.14), + float64(2.718), + } + + fmt.Printf(" 数值类型处理:\\n") + for _, num := range numbers { + result := convertToFloat64(num) + fmt.Printf(" %v (%T) -> %.3f\\n", num, num, result) + } + + // 类型 switch 与接口 + fmt.Printf(" 类型 switch 与接口:\\n") + + shapes := []Shape{ + Circle{Radius: 5}, + Rectangle{Width: 4, Height: 6}, + Triangle{Base: 8, Height: 6}, + } + + for i, shape := range shapes { + fmt.Printf(" 形状 %d: ", i+1) + describeShape(shape) + } + + fmt.Println() +} + +// demonstrateInterfaceAssertions 演示接口类型断言 +func demonstrateInterfaceAssertions() { + fmt.Println("4. 接口类型断言:") + + // 接口到具体类型的断言 + fmt.Printf(" 接口到具体类型的断言:\\n") + + var shape Shape = Circle{Radius: 5} + + // 断言为具体类型 + if circle, ok := shape.(Circle); ok { + fmt.Printf(" 断言为圆形成功: 半径 = %.1f\\n", circle.Radius) + fmt.Printf(" 圆形面积: %.2f\\n", circle.Area()) + fmt.Printf(" 圆形周长: %.2f\\n", circle.Perimeter()) + } + + if rect, ok := shape.(Rectangle); ok { + fmt.Printf(" 断言为矩形成功: %dx%d\\n", int(rect.Width), int(rect.Height)) + } else { + fmt.Printf(" 断言为矩形失败,实际类型: %T\\n", shape) + } + + // 接口到接口的断言 + fmt.Printf(" 接口到接口的断言:\\n") + + var writer io.Writer = &strings.Builder{} + + // 断言为更具体的接口 + if stringWriter, ok := writer.(io.StringWriter); ok { + fmt.Printf(" 支持 StringWriter 接口\\n") + n, err := stringWriter.WriteString("Hello, Interface!") + if err == nil { + fmt.Printf(" 写入字符串成功: %d 字节\\n", n) + } + } + + // 检查接口是否支持其他方法 + if closer, ok := writer.(io.Closer); ok { + fmt.Printf(" 支持 Closer 接口\\n") + closer.Close() + } else { + fmt.Printf(" 不支持 Closer 接口\\n") + } + + // 多接口断言 + fmt.Printf(" 多接口断言:\\n") + + var device Device = &NetworkDevice{ + name: "路由器", + address: "192.168.1.1", + } + + // 检查设备支持的接口 + fmt.Printf(" 设备: %s\\n", device.GetName()) + + if networkable, ok := device.(Networkable); ok { + fmt.Printf(" 支持网络功能: %s\\n", networkable.GetAddress()) + } + + if configurable, ok := device.(Configurable); ok { + config := configurable.GetConfig() + fmt.Printf(" 支持配置功能: %v\\n", config) + } + + if manageable, ok := device.(Manageable); ok { + status := manageable.GetStatus() + fmt.Printf(" 支持管理功能: %s\\n", status) + } + + fmt.Println() +} + +// demonstratePracticalApplications 演示类型断言的实际应用 +func demonstratePracticalApplications() { + fmt.Println("5. 类型断言的实际应用:") + + // 应用1: 错误处理 + fmt.Printf(" 应用1 - 错误处理:\\n") + + errors := []error{ + &ValidationError{Field: "email", Message: "无效的邮箱格式"}, + &NetworkError{Code: 500, Message: "服务器内部错误"}, + fmt.Errorf("普通错误"), + } + + for i, err := range errors { + fmt.Printf(" 错误 %d: ", i+1) + handleError(err) + } + + // 应用2: 插件系统 + fmt.Printf(" 应用2 - 插件系统:\\n") + + plugins := []Plugin{ + &LoggingPlugin{Level: "INFO"}, + &CachePlugin{Size: 1000}, + &SecurityPlugin{Enabled: true}, + } + + pluginManager := PluginManager{plugins: plugins} + pluginManager.ExecuteAll("测试数据") + + // 应用3: 数据序列化 + fmt.Printf(" 应用3 - 数据序列化:\\n") + + serializer := DataSerializer{} + + data := []interface{}{ + Person{Name: "Alice", Age: 30}, + &Person{Name: "Bob", Age: 25}, + []int{1, 2, 3, 4, 5}, + map[string]interface{}{ + "name": "Charlie", + "age": 35, + }, + } + + for i, item := range data { + serialized := serializer.Serialize(item) + fmt.Printf(" 数据 %d: %s\\n", i+1, serialized) + } + + // 应用4: 类型转换器 + fmt.Printf(" 应用4 - 类型转换器:\\n") + + converter := TypeConverter{} + + values := []interface{}{ + 42, + "123", + 3.14, + true, + "false", + } + + for _, value := range values { + strResult := converter.ToString(value) + intResult := converter.ToInt(value) + boolResult := converter.ToBool(value) + + fmt.Printf(" %v (%T):\\n", value, value) + fmt.Printf(" -> 字符串: \\\"%s\\\"\\n", strResult) + fmt.Printf(" -> 整数: %d\\n", intResult) + fmt.Printf(" -> 布尔值: %t\\n", boolResult) + } + + fmt.Println() +} + +// demonstrateAdvancedUsageExamples 演示类型断言的高级用法 +func demonstrateAdvancedUsageExamples() { + fmt.Println("6. 类型断言的高级用法:") + + // 高级用法1: 链式类型断言 + fmt.Printf(" 高级用法1 - 链式类型断言:\\n") + + var value interface{} = &strings.Builder{} + + // 链式断言检查多个接口 + if writer, ok := value.(io.Writer); ok { + fmt.Printf(" 支持 Writer 接口\\n") + + if stringWriter, ok := writer.(io.StringWriter); ok { + fmt.Printf(" 同时支持 StringWriter 接口\\n") + stringWriter.WriteString("链式断言测试") + } + + if stringer, ok := writer.(fmt.Stringer); ok { + fmt.Printf(" 同时支持 Stringer 接口: %s\\n", stringer.String()) + } + } + + // 高级用法2: 类型断言与反射结合 + fmt.Printf(" 高级用法2 - 类型断言与反射结合:\\n") + + inspector := TypeInspector{} + + testValues := []interface{}{ + Person{Name: "Alice", Age: 30}, + &Person{Name: "Bob", Age: 25}, + []Person{{Name: "Charlie", Age: 35}}, + map[string]Person{"key": {Name: "David", Age: 40}}, + } + + for i, value := range testValues { + fmt.Printf(" 检查值 %d:\\n", i+1) + inspector.InspectWithAssertion(value) + } + + // 高级用法3: 动态方法调用 + fmt.Printf(" 高级用法3 - 动态方法调用:\\n") + + objects := []interface{}{ + &Calculator{}, + &Formatter{}, + &Validator{}, + } + + for i, obj := range objects { + fmt.Printf(" 对象 %d:\\n", i+1) + callMethodsDynamically(obj) + } + + // 高级用法4: 接口适配器模式 + fmt.Printf(" 高级用法4 - 接口适配器模式:\\n") + + // 旧接口实现 + oldLogger := &OldLogger{} + + // 使用适配器 + var newLogger Logger = &LoggerAdapter{oldLogger: oldLogger} + newLogger.Log("这是通过适配器记录的日志") + + // 检查适配器是否支持额外功能 + if advancedLogger, ok := newLogger.(AdvancedLogger); ok { + advancedLogger.LogWithContext("错误消息", map[string]string{ + "user_id": "123", + "action": "login", + }) + } + + fmt.Println() +} + +// demonstrateBestPracticesExamples 演示类型断言的最佳实践 +func demonstrateBestPracticesExamples() { + fmt.Println("7. 类型断言的最佳实践:") + + fmt.Printf(" 最佳实践原则:\\n") + fmt.Printf(" 1. 总是使用安全的类型断言(检查 ok 值)\\n") + fmt.Printf(" 2. 优先使用类型 switch 处理多种类型\\n") + fmt.Printf(" 3. 在断言失败时提供有意义的错误处理\\n") + fmt.Printf(" 4. 避免过深的类型断言链\\n") + fmt.Printf(" 5. 考虑使用接口而不是具体类型断言\\n") + + // 最佳实践示例 + fmt.Printf(" 最佳实践示例:\\n") + + // 1. 安全的类型断言 + fmt.Printf(" 1. 安全的类型断言:\\n") + + var data interface{} = "test data" + result, err := safeStringAssertion(data) + if err != nil { + fmt.Printf(" 断言失败: %v\\n", err) + } else { + fmt.Printf(" 断言成功: %s\\n", result) + } + + // 2. 优雅的错误处理 + fmt.Printf(" 2. 优雅的错误处理:\\n") + + values := []interface{}{ + "valid string", + 42, + nil, + } + + for i, value := range values { + result, err := safeStringAssertion(value) + fmt.Printf(" 值 %d: ", i+1) + if err != nil { + fmt.Printf("错误 - %v\\n", err) + } else { + fmt.Printf("成功 - \\\"%s\\\"\\n", result) + } + } + + // 3. 接口优先的设计 + fmt.Printf(" 3. 接口优先的设计:\\n") + + // 好的做法:依赖接口而不是具体类型 + var processor DataProcessor = &JSONProcessor{} + + // 检查是否支持额外功能 + if validator, ok := processor.(DataValidator); ok { + fmt.Printf(" 处理器支持数据验证\\n") + isValid := validator.Validate(`{"name": "Alice"}`) + fmt.Printf(" 数据验证结果: %t\\n", isValid) + } + + if formatter, ok := processor.(DataFormatter); ok { + fmt.Printf(" 处理器支持数据格式化\\n") + formatted := formatter.Format(`{"name":"Alice","age":30}`) + fmt.Printf(" 格式化结果: %s\\n", formatted) + } + + // 4. 性能考虑 + fmt.Printf(" 4. 性能考虑:\\n") + fmt.Printf(" - 类型断言有运行时开销\\n") + fmt.Printf(" - 在热点代码中谨慎使用\\n") + fmt.Printf(" - 考虑缓存断言结果\\n") + fmt.Printf(" - 优先使用具体类型而不是接口\\n") + + // 5. 常见陷阱 + fmt.Printf(" 5. 避免常见陷阱:\\n") + fmt.Printf(" - 不要忽略断言的 ok 返回值\\n") + fmt.Printf(" - 注意 nil 接口的断言行为\\n") + fmt.Printf(" - 理解接口的动态类型和动态值\\n") + fmt.Printf(" - 避免对 nil 值进行类型断言\\n") + + // 演示 nil 接口断言 + var nilInterface interface{} + if str, ok := nilInterface.(string); ok { + fmt.Printf(" nil 断言成功: %s\\n", str) + } else { + fmt.Printf(" nil 接口断言失败(正确行为)\\n") + } + + fmt.Println() +} +/ +/ ========== 类型定义 ========== + +// 基本结构体 +type Person struct { + Name string + Age int +} + +// 几何图形接口和实现 +type Shape interface { + Area() float64 + Perimeter() float64 +} + +type Circle struct { + Radius float64 +} + +func (c Circle) Area() float64 { + return 3.14159 * c.Radius * c.Radius +} + +func (c Circle) Perimeter() float64 { + return 2 * 3.14159 * c.Radius +} + +type Rectangle struct { + Width, Height float64 +} + +func (r Rectangle) Area() float64 { + return r.Width * r.Height +} + +func (r Rectangle) Perimeter() float64 { + return 2 * (r.Width + r.Height) +} + +type Triangle struct { + Base, Height float64 +} + +func (t Triangle) Area() float64 { + return 0.5 * t.Base * t.Height +} + +func (t Triangle) Perimeter() float64 { + // 假设是等腰三角形 + side := (t.Base*t.Base + 4*t.Height*t.Height) / (2 * t.Base) + return t.Base + 2*side +} + +// 设备接口系统 +type Device interface { + GetName() string +} + +type Networkable interface { + GetAddress() string +} + +type Configurable interface { + GetConfig() map[string]string +} + +type Manageable interface { + GetStatus() string +} + +type NetworkDevice struct { + name string + address string +} + +func (nd *NetworkDevice) GetName() string { + return nd.name +} + +func (nd *NetworkDevice) GetAddress() string { + return nd.address +} + +func (nd *NetworkDevice) GetConfig() map[string]string { + return map[string]string{ + "ip": nd.address, + "type": "network", + } +} + +func (nd *NetworkDevice) GetStatus() string { + return "online" +} + +// 错误类型 +type ValidationError struct { + Field string + Message string +} + +func (ve *ValidationError) Error() string { + return fmt.Sprintf("验证错误 [%s]: %s", ve.Field, ve.Message) +} + +type NetworkError struct { + Code int + Message string +} + +func (ne *NetworkError) Error() string { + return fmt.Sprintf("网络错误 [%d]: %s", ne.Code, ne.Message) +} + +// 插件系统 +type Plugin interface { + Execute(data string) string +} + +type LoggingPlugin struct { + Level string +} + +func (lp *LoggingPlugin) Execute(data string) string { + return fmt.Sprintf("[%s] 日志: %s", lp.Level, data) +} + +type CachePlugin struct { + Size int +} + +func (cp *CachePlugin) Execute(data string) string { + return fmt.Sprintf("缓存 (大小:%d): %s", cp.Size, data) +} + +type SecurityPlugin struct { + Enabled bool +} + +func (sp *SecurityPlugin) Execute(data string) string { + if sp.Enabled { + return fmt.Sprintf("安全检查通过: %s", data) + } + return fmt.Sprintf("安全检查跳过: %s", data) +} + +type PluginManager struct { + plugins []Plugin +} + +func (pm *PluginManager) ExecuteAll(data string) { + for i, plugin := range pm.plugins { + result := plugin.Execute(data) + fmt.Printf(" 插件 %d 结果: %s\\n", i+1, result) + } +} + +// 数据序列化器 +type DataSerializer struct{} + +func (ds DataSerializer) Serialize(data interface{}) string { + switch v := data.(type) { + case Person: + return fmt.Sprintf("Person{Name:%s,Age:%d}", v.Name, v.Age) + case *Person: + return fmt.Sprintf("*Person{Name:%s,Age:%d}", v.Name, v.Age) + case []int: + return fmt.Sprintf("[]int%v", v) + case map[string]interface{}: + return fmt.Sprintf("map%v", v) + default: + return fmt.Sprintf("%T(%v)", v, v) + } +} + +// 类型转换器 +type TypeConverter struct{} + +func (tc TypeConverter) ToString(value interface{}) string { + switch v := value.(type) { + case string: + return v + case int: + return strconv.Itoa(v) + case float64: + return strconv.FormatFloat(v, 'f', -1, 64) + case bool: + return strconv.FormatBool(v) + default: + return fmt.Sprintf("%v", v) + } +} + +func (tc TypeConverter) ToInt(value interface{}) int { + switch v := value.(type) { + case int: + return v + case string: + if num, err := strconv.Atoi(v); err == nil { + return num + } + case float64: + return int(v) + case bool: + if v { + return 1 + } + return 0 + } + return 0 +} + +func (tc TypeConverter) ToBool(value interface{}) bool { + switch v := value.(type) { + case bool: + return v + case string: + return v == "true" + case int: + return v != 0 + case float64: + return v != 0.0 + } + return false +} + +// 类型检查器 +type TypeInspector struct{} + +func (ti TypeInspector) InspectWithAssertion(value interface{}) { + // 使用类型断言检查不同类型 + if person, ok := value.(Person); ok { + fmt.Printf(" Person 值类型: %s, %d岁\\n", person.Name, person.Age) + } else if personPtr, ok := value.(*Person); ok { + fmt.Printf(" Person 指针类型: %s, %d岁\\n", personPtr.Name, personPtr.Age) + } else if personSlice, ok := value.([]Person); ok { + fmt.Printf(" Person 切片类型: %d 个元素\\n", len(personSlice)) + } else if personMap, ok := value.(map[string]Person); ok { + fmt.Printf(" Person 映射类型: %d 个键值对\\n", len(personMap)) + } else { + fmt.Printf(" 未知类型: %T\\n", value) + } +} + +// 动态方法调用相关类型 +type Calculator struct{} + +func (c *Calculator) Add(a, b int) int { + return a + b +} + +func (c *Calculator) GetType() string { + return "Calculator" +} + +type Formatter struct{} + +func (f *Formatter) Format(text string) string { + return fmt.Sprintf("[格式化] %s", text) +} + +func (f *Formatter) GetType() string { + return "Formatter" +} + +type Validator struct{} + +func (v *Validator) Validate(data string) bool { + return len(data) > 0 +} + +func (v *Validator) GetType() string { + return "Validator" +} + +// 日志系统 +type Logger interface { + Log(message string) +} + +type AdvancedLogger interface { + LogWithContext(message string, context map[string]string) +} + +type OldLogger struct{} + +func (ol *OldLogger) WriteLog(level, message string) { + fmt.Printf(" [旧日志系统] %s: %s\\n", level, message) +} + +type LoggerAdapter struct { + oldLogger *OldLogger +} + +func (la *LoggerAdapter) Log(message string) { + la.oldLogger.WriteLog("INFO", message) +} + +func (la *LoggerAdapter) LogWithContext(message string, context map[string]string) { + contextStr := "" + for k, v := range context { + contextStr += fmt.Sprintf("%s=%s ", k, v) + } + la.oldLogger.WriteLog("ERROR", fmt.Sprintf("%s [%s]", message, contextStr)) +} + +// 数据处理器接口 +type DataProcessor interface { + Process(data string) string +} + +type DataValidator interface { + Validate(data string) bool +} + +type DataFormatter interface { + Format(data string) string +} + +type JSONProcessor struct{} + +func (jp *JSONProcessor) Process(data string) string { + return fmt.Sprintf("处理JSON: %s", data) +} + +func (jp *JSONProcessor) Validate(data string) bool { + // 简单的JSON验证 + return strings.HasPrefix(data, "{") && strings.HasSuffix(data, "}") +} + +func (jp *JSONProcessor) Format(data string) string { + // 简单的JSON格式化 + return strings.ReplaceAll(data, ",", ", ") +} + +// ========== 辅助函数 ========== + +// 安全处理项目 +func processItemSafely(item interface{}) { + switch v := item.(type) { + case nil: + fmt.Printf(" nil 值\\n") + case string: + fmt.Printf(" 字符串: \\\"%s\\\" (长度: %d)\\n", v, len(v)) + case int: + fmt.Printf(" 整数: %d\\n", v) + case float64: + fmt.Printf(" 浮点数: %.3f\\n", v) + case bool: + fmt.Printf(" 布尔值: %t\\n", v) + default: + fmt.Printf(" 其他类型: %T, 值: %v\\n", v, v) + } +} + +// 使用类型 switch 处理值 +func processWithTypeSwitch(value interface{}) { + switch v := value.(type) { + case nil: + fmt.Printf("nil 值\\n") + case int: + fmt.Printf("整数: %d\\n", v) + case string: + fmt.Printf("字符串: \\\"%s\\\" (长度: %d)\\n", v, len(v)) + case float64: + fmt.Printf("浮点数: %.3f\\n", v) + case bool: + fmt.Printf("布尔值: %t\\n", v) + case []int: + fmt.Printf("整数切片: %v (长度: %d)\\n", v, len(v)) + case map[string]int: + fmt.Printf("字符串到整数的映射: %v (大小: %d)\\n", v, len(v)) + case Person: + fmt.Printf("Person 结构体: %s (%d岁)\\n", v.Name, v.Age) + case *Person: + fmt.Printf("Person 指针: %s (%d岁)\\n", v.Name, v.Age) + default: + fmt.Printf("未知类型: %T, 值: %v\\n", v, v) + } +} + +// 转换为 float64 +func convertToFloat64(value interface{}) float64 { + switch v := value.(type) { + case int: + return float64(v) + case int8: + return float64(v) + case int16: + return float64(v) + case int32: + return float64(v) + case int64: + return float64(v) + case uint: + return float64(v) + case float32: + return float64(v) + case float64: + return v + default: + return 0.0 + } +} + +// 描述形状 +func describeShape(shape Shape) { + area := shape.Area() + perimeter := shape.Perimeter() + + switch s := shape.(type) { + case Circle: + fmt.Printf("圆形 (半径: %.1f) - 面积: %.2f, 周长: %.2f\\n", s.Radius, area, perimeter) + case Rectangle: + fmt.Printf("矩形 (%.1fx%.1f) - 面积: %.2f, 周长: %.2f\\n", s.Width, s.Height, area, perimeter) + case Triangle: + fmt.Printf("三角形 (底: %.1f, 高: %.1f) - 面积: %.2f, 周长: %.2f\\n", s.Base, s.Height, area, perimeter) + default: + fmt.Printf("未知形状 - 面积: %.2f, 周长: %.2f\\n", area, perimeter) + } +} + +// 处理错误 +func handleError(err error) { + switch e := err.(type) { + case *ValidationError: + fmt.Printf("验证错误 - 字段: %s, 消息: %s\\n", e.Field, e.Message) + case *NetworkError: + fmt.Printf("网络错误 - 代码: %d, 消息: %s\\n", e.Code, e.Message) + default: + fmt.Printf("普通错误: %s\\n", err.Error()) + } +} + +// 动态调用方法 +func callMethodsDynamically(obj interface{}) { + // 检查对象类型并调用相应方法 + switch o := obj.(type) { + case *Calculator: + fmt.Printf(" %s: 10 + 20 = %d\\n", o.GetType(), o.Add(10, 20)) + case *Formatter: + fmt.Printf(" %s: %s\\n", o.GetType(), o.Format("测试文本")) + case *Validator: + fmt.Printf(" %s: 验证 'test' = %t\\n", o.GetType(), o.Validate("test")) + default: + fmt.Printf(" 未知对象类型: %T\\n", obj) + } +} + +// 安全的字符串断言 +func safeStringAssertion(value interface{}) (string, error) { + if str, ok := value.(string); ok { + return str, nil + } + return "", fmt.Errorf("无法将 %T 类型断言为 string", value) +} + +/* +运行这个程序: +go run 03-type-assertions.go + +学习要点: +1. 类型断言用于从接口值中提取具体类型 +2. 安全断言返回值和布尔标志,不安全断言可能 panic +3. 类型 switch 是处理多种类型的优雅方式 +4. 接口可以断言为具体类型或其他接口 +5. 类型断言在错误处理、插件系统等场景中很有用 + +类型断言语法: +1. 不安全断言:value.(Type) - 失败时 panic +2. 安全断言:value, ok := value.(Type) - 返回值和布尔标志 +3. 类型 switch:switch value.(type) - 处理多种类型 + +类型断言的应用场景: +1. 错误处理:检查错误的具体类型 +2. 接口功能检查:检查接口是否支持额外方法 +3. 插件系统:动态调用不同插件的方法 +4. 数据序列化:根据类型选择序列化方式 +5. 类型转换:在不同类型间进行转换 + +最佳实践: +1. 总是使用安全的类型断言 +2. 优先使用类型 switch 处理多种类型 +3. 提供有意义的错误处理 +4. 避免过深的类型断言链 +5. 考虑使用接口而不是具体类型断言 + +性能考虑: +1. 类型断言有运行时开销 +2. 在热点代码中谨慎使用 +3. 考虑缓存断言结果 +4. 优先使用具体类型而不是接口 + +常见陷阱: +1. 忽略断言的 ok 返回值 +2. 对 nil 接口进行断言 +3. 不理解接口的动态类型和动态值 +4. 过度使用类型断言而不是接口设计 + +注意事项: +1. nil 接口值的断言总是失败 +2. 类型断言只能用于接口类型 +3. 断言失败时的零值行为 +4. 接口到接口的断言规则 +5. 类型断言与反射的区别 +*/ \ No newline at end of file diff --git a/golang-learning/06-concurrency/01-goroutines.go b/golang-learning/06-concurrency/01-goroutines.go new file mode 100644 index 0000000..9e2fd22 --- /dev/null +++ b/golang-learning/06-concurrency/01-goroutines.go @@ -0,0 +1,738 @@ +/* +01-goroutines.go - Go 语言 Goroutines 详解 + +学习目标: +1. 理解 goroutine 的概念和特性 +2. 掌握 goroutine 的创建和使用 +3. 学会 goroutine 的同步和通信 +4. 了解 goroutine 的调度机制 +5. 掌握 goroutine 的最佳实践 + +知识点: +- goroutine 的基本概念 +- go 关键字的使用 +- goroutine 与线程的区别 +- goroutine 的生命周期 +- goroutine 泄漏的预防 +- 并发安全的考虑 +*/ + +package main + +import ( + "fmt" + "runtime" + "sync" + "time" +) + +func main() { + fmt.Println("=== Go 语言 Goroutines 详解 ===\n") + + // 演示基本的 goroutine + demonstrateBasicGoroutines() + + // 演示 goroutine 的并发执行 + demonstrateConcurrentExecution() + + // 演示 goroutine 的同步 + demonstrateGoroutineSynchronization() + + // 演示 goroutine 的通信 + demonstrateGoroutineCommunication() + + // 演示 goroutine 池 + demonstrateGoroutinePool() + + // 演示 goroutine 的生命周期管理 + demonstrateGoroutineLifecycle() + + // 演示 goroutine 的最佳实践 + demonstrateBestPractices() +} + +// demonstrateBasicGoroutines 演示基本的 goroutine +func demonstrateBasicGoroutines() { + fmt.Println("1. 基本的 Goroutine:") + + // goroutine 的基本概念 + fmt.Printf(" Goroutine 的基本概念:\n") + fmt.Printf(" - 轻量级线程,由 Go 运行时管理\n") + fmt.Printf(" - 使用 go 关键字启动\n") + fmt.Printf(" - 栈大小动态增长,初始只有 2KB\n") + fmt.Printf(" - 由 Go 调度器调度,不是操作系统线程\n") + fmt.Printf(" - 可以创建数百万个 goroutine\n") + + // 基本 goroutine 示例 + fmt.Printf(" 基本 goroutine 示例:\n") + + // 普通函数调用 + fmt.Printf(" 普通函数调用:\n") + sayHello("World") + sayHello("Go") + + // 使用 goroutine + fmt.Printf(" 使用 goroutine:\n") + go sayHello("Goroutine 1") + go sayHello("Goroutine 2") + go sayHello("Goroutine 3") + + // 等待 goroutine 完成 + time.Sleep(100 * time.Millisecond) + + // 匿名函数 goroutine + fmt.Printf(" 匿名函数 goroutine:\n") + + for i := 1; i <= 3; i++ { + go func(id int) { + fmt.Printf(" 匿名 goroutine %d 执行\n", id) + }(i) + } + + time.Sleep(100 * time.Millisecond) + + // 闭包 goroutine + fmt.Printf(" 闭包 goroutine:\n") + + message := "Hello from closure" + go func() { + fmt.Printf(" %s\n", message) + }() + + time.Sleep(100 * time.Millisecond) + + fmt.Println() +} + +// demonstrateConcurrentExecution 演示 goroutine 的并发执行 +func demonstrateConcurrentExecution() { + fmt.Println("2. Goroutine 的并发执行:") + + // 并发执行任务 + fmt.Printf(" 并发执行任务:\n") + + start := time.Now() + + // 串行执行 + fmt.Printf(" 串行执行:\n") + serialStart := time.Now() + task("任务1", 200*time.Millisecond) + task("任务2", 200*time.Millisecond) + task("任务3", 200*time.Millisecond) + serialDuration := time.Since(serialStart) + fmt.Printf(" 串行执行耗时: %v\n", serialDuration) + + // 并发执行 + fmt.Printf(" 并发执行:\n") + concurrentStart := time.Now() + + var wg sync.WaitGroup + wg.Add(3) + + go func() { + defer wg.Done() + task("并发任务1", 200*time.Millisecond) + }() + + go func() { + defer wg.Done() + task("并发任务2", 200*time.Millisecond) + }() + + go func() { + defer wg.Done() + task("并发任务3", 200*time.Millisecond) + }() + + wg.Wait() + concurrentDuration := time.Since(concurrentStart) + fmt.Printf(" 并发执行耗时: %v\n", concurrentDuration) + + // CPU 密集型任务 + fmt.Printf(" CPU 密集型任务:\n") + + numCPU := runtime.NumCPU() + fmt.Printf(" CPU 核心数: %d\n", numCPU) + + // 设置使用的 CPU 核心数 + runtime.GOMAXPROCS(numCPU) + + cpuStart := time.Now() + var cpuWg sync.WaitGroup + + for i := 0; i < numCPU; i++ { + cpuWg.Add(1) + go func(id int) { + defer cpuWg.Done() + result := fibonacci(35) + fmt.Printf(" Goroutine %d: fibonacci(35) = %d\n", id, result) + }(i) + } + + cpuWg.Wait() + cpuDuration := time.Since(cpuStart) + fmt.Printf(" CPU 密集型任务耗时: %v\n", cpuDuration) + + totalDuration := time.Since(start) + fmt.Printf(" 总耗时: %v\n", totalDuration) + + fmt.Println() +} + +// demonstrateGoroutineSynchronization 演示 goroutine 的同步 +func demonstrateGoroutineSynchronization() { + fmt.Println("3. Goroutine 的同步:") + + // 使用 WaitGroup 同步 + fmt.Printf(" 使用 WaitGroup 同步:\n") + + var wg sync.WaitGroup + + for i := 1; i <= 5; i++ { + wg.Add(1) + go func(id int) { + defer wg.Done() + fmt.Printf(" Worker %d 开始工作\n", id) + time.Sleep(time.Duration(id*100) * time.Millisecond) + fmt.Printf(" Worker %d 完成工作\n", id) + }(i) + } + + fmt.Printf(" 等待所有 worker 完成...\n") + wg.Wait() + fmt.Printf(" 所有 worker 已完成\n") + + // 使用 Mutex 保护共享资源 + fmt.Printf(" 使用 Mutex 保护共享资源:\n") + + var counter Counter + var counterWg sync.WaitGroup + + // 启动多个 goroutine 增加计数器 + for i := 0; i < 10; i++ { + counterWg.Add(1) + go func(id int) { + defer counterWg.Done() + for j := 0; j < 1000; j++ { + counter.Increment() + } + fmt.Printf(" Goroutine %d 完成\n", id) + }(i) + } + + counterWg.Wait() + fmt.Printf(" 最终计数器值: %d\n", counter.Value()) + + // 使用 Once 确保只执行一次 + fmt.Printf(" 使用 Once 确保只执行一次:\n") + + var once sync.Once + var onceWg sync.WaitGroup + + for i := 0; i < 5; i++ { + onceWg.Add(1) + go func(id int) { + defer onceWg.Done() + once.Do(func() { + fmt.Printf(" 初始化操作只执行一次 (来自 goroutine %d)\n", id) + }) + fmt.Printf(" Goroutine %d 执行完毕\n", id) + }(i) + } + + onceWg.Wait() + + fmt.Println() +} + +// demonstrateGoroutineCommunication 演示 goroutine 的通信 +func demonstrateGoroutineCommunication() { + fmt.Println("4. Goroutine 的通信:") + + // 使用 channel 通信 + fmt.Printf(" 使用 channel 通信:\n") + + // 简单的 channel 通信 + ch := make(chan string) + + go func() { + time.Sleep(100 * time.Millisecond) + ch <- "Hello from goroutine" + }() + + message := <-ch + fmt.Printf(" 接收到消息: %s\n", message) + + // 生产者-消费者模式 + fmt.Printf(" 生产者-消费者模式:\n") + + jobs := make(chan int, 5) + results := make(chan int, 5) + + // 启动 3 个 worker + for w := 1; w <= 3; w++ { + go worker(w, jobs, results) + } + + // 发送 5 个任务 + for j := 1; j <= 5; j++ { + jobs <- j + } + close(jobs) + + // 收集结果 + for r := 1; r <= 5; r++ { + result := <-results + fmt.Printf(" 结果: %d\n", result) + } + + // 扇出/扇入模式 + fmt.Printf(" 扇出/扇入模式:\n") + + input := make(chan int) + output1 := make(chan int) + output2 := make(chan int) + + // 扇出:一个输入分发到多个处理器 + go func() { + for i := 1; i <= 10; i++ { + input <- i + } + close(input) + }() + + // 处理器 1 + go func() { + for num := range input { + output1 <- num * 2 + } + close(output1) + }() + + // 处理器 2 + go func() { + for num := range input { + output2 <- num * 3 + } + close(output2) + }() + + // 扇入:合并多个输出 + merged := fanIn(output1, output2) + + fmt.Printf(" 合并结果: ") + for result := range merged { + fmt.Printf("%d ", result) + } + fmt.Printf("\n") + + fmt.Println() +} + +// demonstrateGoroutinePool 演示 goroutine 池 +func demonstrateGoroutinePool() { + fmt.Println("5. Goroutine 池:") + + // 固定大小的 goroutine 池 + fmt.Printf(" 固定大小的 goroutine 池:\n") + + const numWorkers = 3 + const numJobs = 10 + + jobs := make(chan Job, numJobs) + results := make(chan Result, numJobs) + + // 启动 worker 池 + for w := 1; w <= numWorkers; w++ { + go jobWorker(w, jobs, results) + } + + // 发送任务 + for j := 1; j <= numJobs; j++ { + jobs <- Job{ID: j, Data: fmt.Sprintf("任务数据 %d", j)} + } + close(jobs) + + // 收集结果 + for r := 1; r <= numJobs; r++ { + result := <-results + fmt.Printf(" %s\n", result.Message) + } + + // 动态 goroutine 池 + fmt.Printf(" 动态 goroutine 池:\n") + + pool := NewWorkerPool(5, 20) + pool.Start() + + // 提交任务 + for i := 1; i <= 15; i++ { + taskID := i + pool.Submit(func() { + fmt.Printf(" 执行任务 %d\n", taskID) + time.Sleep(100 * time.Millisecond) + }) + } + + pool.Stop() + + fmt.Println() +} + +// demonstrateGoroutineLifecycle 演示 goroutine 的生命周期管理 +func demonstrateGoroutineLifecycle() { + fmt.Println("6. Goroutine 的生命周期管理:") + + // 优雅关闭 + fmt.Printf(" 优雅关闭:\n") + + done := make(chan bool) + quit := make(chan bool) + + go func() { + for { + select { + case <-quit: + fmt.Printf(" 接收到退出信号,正在清理...\n") + time.Sleep(100 * time.Millisecond) + fmt.Printf(" 清理完成\n") + done <- true + return + default: + fmt.Printf(" 工作中...\n") + time.Sleep(200 * time.Millisecond) + } + } + }() + + time.Sleep(500 * time.Millisecond) + fmt.Printf(" 发送退出信号\n") + quit <- true + <-done + fmt.Printf(" Goroutine 已优雅退出\n") + + // 超时控制 + fmt.Printf(" 超时控制:\n") + + timeout := time.After(300 * time.Millisecond) + finished := make(chan bool) + + go func() { + time.Sleep(500 * time.Millisecond) // 模拟长时间运行的任务 + finished <- true + }() + + select { + case <-finished: + fmt.Printf(" 任务完成\n") + case <-timeout: + fmt.Printf(" 任务超时\n") + } + + // 错误处理 + fmt.Printf(" 错误处理:\n") + + errorCh := make(chan error, 1) + + go func() { + defer func() { + if r := recover(); r != nil { + errorCh <- fmt.Errorf("goroutine panic: %v", r) + } + }() + + // 模拟可能 panic 的操作 + if time.Now().UnixNano()%2 == 0 { + panic("模拟 panic") + } + + fmt.Printf(" 任务正常完成\n") + errorCh <- nil + }() + + if err := <-errorCh; err != nil { + fmt.Printf(" 捕获到错误: %v\n", err) + } + + fmt.Println() +} + +// demonstrateBestPractices 演示 goroutine 的最佳实践 +func demonstrateBestPractices() { + fmt.Println("7. Goroutine 的最佳实践:") + + fmt.Printf(" 最佳实践原则:\n") + fmt.Printf(" 1. 避免 goroutine 泄漏\n") + fmt.Printf(" 2. 使用 context 进行取消和超时控制\n") + fmt.Printf(" 3. 合理控制 goroutine 数量\n") + fmt.Printf(" 4. 使用 channel 进行通信而不是共享内存\n") + fmt.Printf(" 5. 正确处理 panic 和错误\n") + + // 避免 goroutine 泄漏 + fmt.Printf(" 避免 goroutine 泄漏:\n") + + // 错误示例:可能导致 goroutine 泄漏 + fmt.Printf(" 错误示例 - 可能导致泄漏:\n") + leakyCh := make(chan int) + go func() { + // 这个 goroutine 可能永远阻塞 + leakyCh <- 42 + }() + // 如果不读取 channel,goroutine 会泄漏 + + // 正确示例:使用缓冲 channel 或确保读取 + fmt.Printf(" 正确示例 - 避免泄漏:\n") + safeCh := make(chan int, 1) // 缓冲 channel + go func() { + safeCh <- 42 + fmt.Printf(" 安全的 goroutine 完成\n") + }() + <-safeCh + + // 使用 defer 清理资源 + fmt.Printf(" 使用 defer 清理资源:\n") + + var cleanupWg sync.WaitGroup + cleanupWg.Add(1) + + go func() { + defer cleanupWg.Done() + defer fmt.Printf(" 资源已清理\n") + + fmt.Printf(" 执行任务...\n") + time.Sleep(100 * time.Millisecond) + }() + + cleanupWg.Wait() + + // 监控 goroutine 数量 + fmt.Printf(" 监控 goroutine 数量:\n") + fmt.Printf(" 当前 goroutine 数量: %d\n", runtime.NumGoroutine()) + + // 启动一些 goroutine + var monitorWg sync.WaitGroup + for i := 0; i < 5; i++ { + monitorWg.Add(1) + go func(id int) { + defer monitorWg.Done() + time.Sleep(100 * time.Millisecond) + }(i) + } + + fmt.Printf(" 启动 5 个 goroutine 后: %d\n", runtime.NumGoroutine()) + monitorWg.Wait() + fmt.Printf(" goroutine 完成后: %d\n", runtime.NumGoroutine()) + + fmt.Println() +} + +// ========== 辅助函数和类型定义 ========== + +// sayHello 简单的问候函数 +func sayHello(name string) { + fmt.Printf(" Hello, %s!\n", name) +} + +// task 模拟一个耗时任务 +func task(name string, duration time.Duration) { + fmt.Printf(" %s 开始执行\n", name) + time.Sleep(duration) + fmt.Printf(" %s 执行完成\n", name) +} + +// fibonacci 计算斐波那契数列(CPU 密集型任务) +func fibonacci(n int) int { + if n <= 1 { + return n + } + return fibonacci(n-1) + fibonacci(n-2) +} + +// Counter 线程安全的计数器 +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 +} + +// worker 工作函数 +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 + } +} + +// fanIn 扇入函数,合并多个 channel +func fanIn(input1, input2 <-chan int) <-chan int { + output := make(chan int) + go func() { + defer close(output) + for input1 != nil || input2 != nil { + select { + case val, ok := <-input1: + if !ok { + input1 = nil + } else { + output <- val + } + case val, ok := <-input2: + if !ok { + input2 = nil + } else { + output <- val + } + } + } + }() + return output +} + +// Job 任务结构 +type Job struct { + ID int + Data string +} + +// Result 结果结构 +type Result struct { + JobID int + Message string +} + +// jobWorker 任务处理器 +func jobWorker(id int, jobs <-chan Job, results chan<- Result) { + for job := range jobs { + fmt.Printf(" Worker %d 处理任务 %d\n", id, job.ID) + time.Sleep(100 * time.Millisecond) + results <- Result{ + JobID: job.ID, + Message: fmt.Sprintf("Worker %d 完成任务 %d: %s", id, job.ID, job.Data), + } + } +} + +// WorkerPool 动态工作池 +type WorkerPool struct { + maxWorkers int + taskQueue chan func() + quit chan bool + wg sync.WaitGroup +} + +// NewWorkerPool 创建新的工作池 +func NewWorkerPool(maxWorkers, queueSize int) *WorkerPool { + return &WorkerPool{ + maxWorkers: maxWorkers, + taskQueue: make(chan func(), queueSize), + quit: make(chan bool), + } +} + +// Start 启动工作池 +func (p *WorkerPool) Start() { + for i := 0; i < p.maxWorkers; i++ { + p.wg.Add(1) + go p.worker(i + 1) + } +} + +// Submit 提交任务 +func (p *WorkerPool) Submit(task func()) { + select { + case p.taskQueue <- task: + default: + fmt.Printf(" 任务队列已满,任务被丢弃\n") + } +} + +// Stop 停止工作池 +func (p *WorkerPool) Stop() { + close(p.taskQueue) + p.wg.Wait() +} + +// worker 工作池的工作函数 +func (p *WorkerPool) worker(id int) { + defer p.wg.Done() + for task := range p.taskQueue { + fmt.Printf(" Pool Worker %d 执行任务\n", id) + task() + } + fmt.Printf(" Pool Worker %d 退出\n", id) +} + +/* +运行这个程序: +go run 01-goroutines.go + +学习要点: +1. Goroutine 是 Go 语言的轻量级线程 +2. 使用 go 关键字启动 goroutine +3. Goroutine 之间需要同步和通信机制 +4. 使用 WaitGroup、Mutex、Once 等���步原语 +5. 通过 channel 进行 goroutine 间通信 + +Goroutine 的特性: +1. 轻量级:初始栈大小只有 2KB +2. 动态增长:栈大小可以动态调整 +3. 多路复用:多个 goroutine 可以在少数 OS 线程上运行 +4. 协作式调度:由 Go 运行时调度 +5. 高效通信:通过 channel 进行通信 + +同步机制: +1. WaitGroup:等待一组 goroutine 完成 +2. Mutex:互斥锁,保护共享资源 +3. RWMutex:读写锁,允许多个读者 +4. Once:确保函数只执行一次 +5. Cond:条件变量,用于等待条件 + +通信模式: +1. 简单通信:通过 channel 发送和接收数据 +2. 生产者-消费者:使用缓冲 channel +3. 扇出/扇入:一对多和多对一的通信 +4. 管道:链式处理数据 +5. 工作池:固定数量的 worker 处理任务 + +最佳实践: +1. 避免 goroutine 泄漏 +2. 使用 context 进行取消和超时控制 +3. 合理控制 goroutine 数量 +4. 使用 channel 进行通信而不是共享内存 +5. 正确处理 panic 和错误 +6. 使用 defer 清理资源 +7. 监控 goroutine 数量 + +常见陷阱: +1. 忘记等待 goroutine 完成 +2. 在循环中使用闭包时的变量捕获问题 +3. 无缓冲 channel 导致的死锁 +4. goroutine 泄漏 +5. 竞态条件 + +性能考虑: +1. Goroutine 创建成本很低 +2. 上下文切换开销小 +3. 内存使用效率高 +4. 适合 I/O 密集型任务 +5. CPU 密集型任务需要考虑 GOMAXPROCS + +注意事项: +1. main 函数退出时所有 goroutine 都会终止 +2. goroutine 中的 panic 会导致整个程序崩溃 +3. 共享变量需要同步保护 +4. channel 的关闭只能由发送方执行 +5. 避免在 goroutine 中使用全局变量 +*/ diff --git a/golang-learning/06-concurrency/02-channels.go b/golang-learning/06-concurrency/02-channels.go new file mode 100644 index 0000000..8cda5de --- /dev/null +++ b/golang-learning/06-concurrency/02-channels.go @@ -0,0 +1,840 @@ +/* +02-channels.go - Go 语言 Channels 详解 + +学习目标: +1. 理解 channel 的概念和特性 +2. 掌握 channel 的创建和使用 +3. 学会不同类型的 channel +4. 了解 channel 的方向性 +5. 掌握 channel 的关闭和检测 + +知识点: +- channel 的基本概念 +- 无缓冲和有缓冲 channel +- channel 的方向性 +- channel 的关闭 +- range 和 select 与 channel +- channel 的常见模式 +*/ + +package main + +import ( + "fmt" + "math/rand" + "sync" + "time" +) + +func main() { + fmt.Println("=== Go 语言 Channels 详解 ===\n") + + // 演示基本的 channel + demonstrateBasicChannels() + + // 演示缓冲 channel + demonstrateBufferedChannels() + + // 演示 channel 的方向性 + demonstrateChannelDirections() + + // 演示 channel 的关闭 + demonstrateChannelClosing() + + // 演示 channel 与 range + demonstrateChannelRange() + + // 演示 channel 的常见模式 + demonstrateChannelPatterns() + + // 演示 channel 的高级用法 + demonstrateAdvancedChannelUsage() +} + +// demonstrateBasicChannels 演示基本的 channel +func demonstrateBasicChannels() { + fmt.Println("1. 基本的 Channel:") + + // channel 的基本概念 + fmt.Printf(" Channel 的基本概念:\n") + fmt.Printf(" - Go 语言的核心特性,用于 goroutine 间通信\n") + fmt.Printf(" - 类型安全的管道,可以传递特定类型的数据\n") + fmt.Printf(" - 默认是无缓冲的,发送和接收会阻塞\n") + fmt.Printf(" - 遵循 'Don't communicate by sharing memory; share memory by communicating'\n") + + // 创建和使用 channel + fmt.Printf(" 创建和使用 channel:\n") + + // 创建一个 int 类型的 channel + ch := make(chan int) + + // 在 goroutine 中发送数据 + go func() { + fmt.Printf(" 发送数据到 channel\n") + ch <- 42 + }() + + // 从 channel 接收数据 + value := <-ch + fmt.Printf(" 从 channel 接收到: %d\n", value) + + // 双向通信 + fmt.Printf(" 双向通信:\n") + + messages := make(chan string) + responses := make(chan string) + + // 启动一个 echo 服务 + go echoServer(messages, responses) + + // 发送消息并接收响应 + messages <- "Hello" + response := <-responses + fmt.Printf(" 发送: Hello, 接收: %s\n", response) + + messages <- "World" + response = <-responses + fmt.Printf(" 发送: World, 接收: %s\n", response) + + // 关闭 channels + close(messages) + close(responses) + + // 同步使用 channel + fmt.Printf(" 同步使用 channel:\n") + + done := make(chan bool) + + go func() { + fmt.Printf(" 执行异步任务...\n") + time.Sleep(200 * time.Millisecond) + fmt.Printf(" 异步任务完成\n") + done <- true + }() + + fmt.Printf(" 等待异步任务完成...\n") + <-done + fmt.Printf(" 主程序继续执行\n") + + fmt.Println() +} + +// demonstrateBufferedChannels 演示缓冲 channel +func demonstrateBufferedChannels() { + fmt.Println("2. 缓冲 Channel:") + + // 无缓冲 vs 有缓冲 + fmt.Printf(" 无缓冲 vs 有缓冲:\n") + + // 无缓冲 channel(同步) + fmt.Printf(" 无缓冲 channel (同步):\n") + unbuffered := make(chan string) + + go func() { + fmt.Printf(" 发送到无缓冲 channel\n") + unbuffered <- "sync message" + fmt.Printf(" 无缓冲 channel 发送完成\n") + }() + + time.Sleep(100 * time.Millisecond) // 让 goroutine 先运行 + msg := <-unbuffered + fmt.Printf(" 接收到: %s\n", msg) + + // 有缓冲 channel(异步) + fmt.Printf(" 有缓冲 channel (异步):\n") + buffered := make(chan string, 2) + + fmt.Printf(" 发送到有缓冲 channel\n") + buffered <- "async message 1" + buffered <- "async message 2" + fmt.Printf(" 有缓冲 channel 发送完成(未阻塞)\n") + + fmt.Printf(" 接收到: %s\n", <-buffered) + fmt.Printf(" 接收到: %s\n", <-buffered) + + // 缓冲区满时的行为 + fmt.Printf(" 缓冲区满时的行为:\n") + + fullBuffer := make(chan int, 2) + + // 填满缓冲区 + fullBuffer <- 1 + fullBuffer <- 2 + fmt.Printf(" 缓冲区已满 (2/2)\n") + + // 尝试再发送一个值(会阻塞) + go func() { + fmt.Printf(" 尝试发送第三个值(会阻塞)\n") + fullBuffer <- 3 + fmt.Printf(" 第三个值发送成功\n") + }() + + time.Sleep(100 * time.Millisecond) + fmt.Printf(" 接收一个值: %d\n", <-fullBuffer) + time.Sleep(100 * time.Millisecond) + fmt.Printf(" 接收一个值: %d\n", <-fullBuffer) + fmt.Printf(" 接收一个值: %d\n", <-fullBuffer) + + // 生产者-消费者模式 + fmt.Printf(" 生产者-消费者模式:\n") + + const bufferSize = 5 + const numProducers = 2 + const numConsumers = 3 + const numItems = 10 + + items := make(chan int, bufferSize) + var wg sync.WaitGroup + + // 启动生产者 + for i := 0; i < numProducers; i++ { + wg.Add(1) + go producer(i+1, items, numItems/numProducers, &wg) + } + + // 启动消费者 + for i := 0; i < numConsumers; i++ { + wg.Add(1) + go consumer(i+1, items, &wg) + } + + // 等待所有生产者完成,然后关闭 channel + go func() { + wg.Wait() + close(items) + }() + + // 等待一段时间让消费者处理完所有项目 + time.Sleep(500 * time.Millisecond) + + fmt.Println() +} + +// demonstrateChannelDirections 演示 channel 的方向性 +func demonstrateChannelDirections() { + fmt.Println("3. Channel 的方向性:") + + // 双向 channel + fmt.Printf(" 双向 channel:\n") + + bidirectional := make(chan string) + + go func() { + bidirectional <- "双向消息" + }() + + message := <-bidirectional + fmt.Printf(" 接收到: %s\n", message) + + // 只发送 channel + fmt.Printf(" 只发送 channel:\n") + + sendOnly := make(chan int) + go sender(sendOnly) + + value := <-sendOnly + fmt.Printf(" 从只发送 channel 接收到: %d\n", value) + + // 只接收 channel + fmt.Printf(" 只接收 channel:\n") + + receiveOnly := make(chan int, 1) + receiveOnly <- 100 + + go receiver(receiveOnly) + time.Sleep(100 * time.Millisecond) + + // 管道模式 + fmt.Printf(" 管道模式:\n") + + numbers := make(chan int) + squares := make(chan int) + cubes := make(chan int) + + // 启动管道 + go generateNumbers(numbers) + go squareNumbers(numbers, squares) + go cubeNumbers(squares, cubes) + + // 读取最终结果 + for i := 0; i < 5; i++ { + result := <-cubes + fmt.Printf(" 管道结果: %d\n", result) + } + + fmt.Println() +} + +// demonstrateChannelClosing 演示 channel 的关闭 +func demonstrateChannelClosing() { + fmt.Println("4. Channel 的关闭:") + + // 基本的 channel 关闭 + fmt.Printf(" 基本的 channel 关闭:\n") + + ch := make(chan int, 3) + + // 发送一些值 + ch <- 1 + ch <- 2 + ch <- 3 + + // 关闭 channel + close(ch) + + // 从已关闭的 channel 读取 + for i := 0; i < 4; i++ { + value, ok := <-ch + if ok { + fmt.Printf(" 接收到值: %d\n", value) + } else { + fmt.Printf(" channel 已关闭,接收到零值: %d\n", value) + } + } + + // 检测 channel 是否关闭 + fmt.Printf(" 检测 channel 是否关闭:\n") + + status := make(chan string, 2) + status <- "active" + status <- "inactive" + close(status) + + for { + value, ok := <-status + if !ok { + fmt.Printf(" channel 已关闭,退出循环\n") + break + } + fmt.Printf(" 状态: %s\n", value) + } + + // 多个发送者的关闭模式 + fmt.Printf(" 多个发送者的关闭模式:\n") + + data := make(chan int) + done := make(chan bool) + + // 启动多个发送者 + for i := 1; i <= 3; i++ { + go multipleSender(i, data, done) + } + + // 接收数据 + go func() { + for value := range data { + fmt.Printf(" 接收到: %d\n", value) + } + fmt.Printf(" 数据接收完成\n") + }() + + // 等待一段时间后通知所有发送者停止 + time.Sleep(300 * time.Millisecond) + close(done) + + // 等待发送者停止后关闭数据 channel + time.Sleep(100 * time.Millisecond) + close(data) + + time.Sleep(100 * time.Millisecond) + + fmt.Println() +} + +// demonstrateChannelRange 演示 channel 与 range +func demonstrateChannelRange() { + fmt.Println("5. Channel 与 Range:") + + // 使用 range 遍历 channel + fmt.Printf(" 使用 range 遍历 channel:\n") + + numbers := make(chan int) + + // 发送数据 + go func() { + for i := 1; i <= 5; i++ { + numbers <- i + time.Sleep(50 * time.Millisecond) + } + close(numbers) + }() + + // 使用 range 接收数据 + for num := range numbers { + fmt.Printf(" 接收到数字: %d\n", num) + } + + // 斐波那契数列生成器 + fmt.Printf(" 斐波那契数列生成器:\n") + + fib := fibonacci(10) + for value := range fib { + fmt.Printf(" 斐波那契: %d\n", value) + } + + // 素数生成器 + fmt.Printf(" 素数生成器:\n") + + primes := sieve(30) + fmt.Printf(" 30 以内的素数: ") + for prime := range primes { + fmt.Printf("%d ", prime) + } + fmt.Printf("\n") + + fmt.Println() +} + +// demonstrateChannelPatterns 演示 channel 的常见模式 +func demonstrateChannelPatterns() { + fmt.Println("6. Channel 的常见模式:") + + // 扇出模式(一个输入,多个输出) + fmt.Printf(" 扇出模式:\n") + + input := make(chan int) + output1 := make(chan int) + output2 := make(chan int) + output3 := make(chan int) + + // 扇出 + go fanOut(input, output1, output2, output3) + + // 发送数据 + go func() { + for i := 1; i <= 6; i++ { + input <- i + } + close(input) + }() + + // 接收数据 + var wg sync.WaitGroup + wg.Add(3) + + go func() { + defer wg.Done() + for value := range output1 { + fmt.Printf(" 输出1: %d\n", value) + } + }() + + go func() { + defer wg.Done() + for value := range output2 { + fmt.Printf(" 输出2: %d\n", value) + } + }() + + go func() { + defer wg.Done() + for value := range output3 { + fmt.Printf(" 输出3: %d\n", value) + } + }() + + wg.Wait() + + // 扇入模式(多个输入,一个输出) + fmt.Printf(" 扇入模式:\n") + + input1 := make(chan string) + input2 := make(chan string) + input3 := make(chan string) + + // 启动输入源 + go func() { + for i := 1; i <= 3; i++ { + input1 <- fmt.Sprintf("源1-%d", i) + time.Sleep(100 * time.Millisecond) + } + close(input1) + }() + + go func() { + for i := 1; i <= 3; i++ { + input2 <- fmt.Sprintf("源2-%d", i) + time.Sleep(150 * time.Millisecond) + } + close(input2) + }() + + go func() { + for i := 1; i <= 3; i++ { + input3 <- fmt.Sprintf("源3-%d", i) + time.Sleep(200 * time.Millisecond) + } + close(input3) + }() + + // 扇入 + merged := fanInMultiple(input1, input2, input3) + + fmt.Printf(" 合并结果:\n") + for result := range merged { + fmt.Printf(" %s\n", result) + } + + // 工作池模式 + fmt.Printf(" 工作池模式:\n") + + jobs := make(chan WorkJob, 10) + results := make(chan WorkResult, 10) + + // 启动工作池 + const numWorkers = 3 + for w := 1; w <= numWorkers; w++ { + go workPoolWorker(w, jobs, results) + } + + // 发送任务 + for j := 1; j <= 9; j++ { + jobs <- WorkJob{ID: j, Data: fmt.Sprintf("任务-%d", j)} + } + close(jobs) + + // 收集结果 + for r := 1; r <= 9; r++ { + result := <-results + fmt.Printf(" %s\n", result.Message) + } + + fmt.Println() +} + +// demonstrateAdvancedChannelUsage 演示 channel 的高级用法 +func demonstrateAdvancedChannelUsage() { + fmt.Println("7. Channel 的高级用法:") + + // 超时模式 + fmt.Printf(" 超时模式:\n") + + slowCh := make(chan string) + + go func() { + time.Sleep(300 * time.Millisecond) + slowCh <- "慢速响应" + }() + + select { + case result := <-slowCh: + fmt.Printf(" 接收到: %s\n", result) + case <-time.After(200 * time.Millisecond): + fmt.Printf(" 操作超时\n") + } + + // 非阻塞操作 + fmt.Printf(" 非阻塞操作:\n") + + nonBlockingCh := make(chan int, 1) + + // 非阻塞发送 + select { + case nonBlockingCh <- 42: + fmt.Printf(" 非阻塞发送成功\n") + default: + fmt.Printf(" 非阻塞发送失败,channel 已满\n") + } + + // 非阻塞接收 + select { + case value := <-nonBlockingCh: + fmt.Printf(" 非阻塞接收成功: %d\n", value) + default: + fmt.Printf(" 非阻塞接收失败,channel 为空\n") + } + + // 心跳模式 + fmt.Printf(" 心跳模式:\n") + + heartbeat := time.NewTicker(100 * time.Millisecond) + defer heartbeat.Stop() + + timeout := time.After(350 * time.Millisecond) + + for { + select { + case <-heartbeat.C: + fmt.Printf(" 心跳\n") + case <-timeout: + fmt.Printf(" 心跳监控结束\n") + goto heartbeatEnd + } + } +heartbeatEnd: + + // 速率限制 + fmt.Printf(" 速率限制:\n") + + rateLimiter := time.NewTicker(100 * time.Millisecond) + defer rateLimiter.Stop() + + requests := make(chan int, 5) + for i := 1; i <= 5; i++ { + requests <- i + } + close(requests) + + for req := range requests { + <-rateLimiter.C // 等待速率限制器 + fmt.Printf(" 处理请求 %d (限速)\n", req) + } + + fmt.Println() +} + +// ========== 辅助函数和类型定义 ========== + +// echoServer 简单的回声服务器 +func echoServer(messages <-chan string, responses chan<- string) { + for msg := range messages { + responses <- "Echo: " + msg + } +} + +// producer 生产者函数 +func producer(id int, items chan<- int, count int, wg *sync.WaitGroup) { + defer wg.Done() + for i := 0; i < count; i++ { + item := id*100 + i + items <- item + fmt.Printf(" 生产者 %d 生产: %d\n", id, item) + time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond) + } + fmt.Printf(" 生产者 %d 完成\n", id) +} + +// consumer 消费者函数 +func consumer(id int, items <-chan int, wg *sync.WaitGroup) { + defer wg.Done() + for item := range items { + fmt.Printf(" 消费者 %d 消费: %d\n", id, item) + time.Sleep(time.Duration(rand.Intn(150)) * time.Millisecond) + } + fmt.Printf(" 消费者 %d 完成\n", id) +} + +// sender 只发送函数 +func sender(ch chan<- int) { + ch <- 42 + close(ch) +} + +// receiver 只接收函数 +func receiver(ch <-chan int) { + value := <-ch + fmt.Printf(" 只接收 channel 接收到: %d\n", value) +} + +// generateNumbers 生成数字 +func generateNumbers(out chan<- int) { + for i := 1; i <= 5; i++ { + out <- i + } + close(out) +} + +// squareNumbers 计算平方 +func squareNumbers(in <-chan int, out chan<- int) { + for num := range in { + out <- num * num + } + close(out) +} + +// cubeNumbers 计算立方 +func cubeNumbers(in <-chan int, out chan<- int) { + for num := range in { + out <- num * num * num + } + close(out) +} + +// multipleSender 多发送者函数 +func multipleSender(id int, data chan<- int, done <-chan bool) { + for { + select { + case data <- id*10 + rand.Intn(10): + time.Sleep(100 * time.Millisecond) + case <-done: + fmt.Printf(" 发送者 %d 停止\n", id) + return + } + } +} + +// fibonacci 斐波那契生成器 +func fibonacci(n int) <-chan int { + ch := make(chan int) + go func() { + defer close(ch) + a, b := 0, 1 + for i := 0; i < n; i++ { + ch <- a + a, b = b, a+b + } + }() + return ch +} + +// sieve 埃拉托斯特尼筛法生成素数 +func sieve(max int) <-chan int { + ch := make(chan int) + go func() { + defer close(ch) + isPrime := make([]bool, max+1) + for i := 2; i <= max; i++ { + isPrime[i] = true + } + + for i := 2; i*i <= max; i++ { + if isPrime[i] { + for j := i * i; j <= max; j += i { + isPrime[j] = false + } + } + } + + for i := 2; i <= max; i++ { + if isPrime[i] { + ch <- i + } + } + }() + return ch +} + +// fanOut 扇出函数 +func fanOut(input <-chan int, outputs ...chan<- int) { + go func() { + defer func() { + for _, output := range outputs { + close(output) + } + }() + + i := 0 + for value := range input { + outputs[i%len(outputs)] <- value + i++ + } + }() +} + +// fanInMultiple 多路扇入函数 +func fanInMultiple(inputs ...<-chan string) <-chan string { + output := make(chan string) + var wg sync.WaitGroup + + // 为每个输入启动一个 goroutine + for _, input := range inputs { + wg.Add(1) + go func(ch <-chan string) { + defer wg.Done() + for value := range ch { + output <- value + } + }(input) + } + + // 等待所有输入完成后关闭输出 + go func() { + wg.Wait() + close(output) + }() + + return output +} + +// WorkJob 工作任务 +type WorkJob struct { + ID int + Data string +} + +// WorkResult 工作结果 +type WorkResult struct { + JobID int + Message string +} + +// workPoolWorker 工作池工作者 +func workPoolWorker(id int, jobs <-chan WorkJob, results chan<- WorkResult) { + for job := range jobs { + fmt.Printf(" 工作者 %d 开始处理任务 %d\n", id, job.ID) + time.Sleep(time.Duration(rand.Intn(200)) * time.Millisecond) + + results <- WorkResult{ + JobID: job.ID, + Message: fmt.Sprintf("工作者 %d 完成任务 %d: %s", id, job.ID, job.Data), + } + } +} + +/* +运行这个程序: +go run 02-channels.go + +学习要点: +1. Channel 是 Go 语言中 goroutine 间通信的主要方式 +2. Channel 有无缓冲和有缓冲两种类型 +3. Channel 具有方向性,可以限制为只发送或只接收 +4. Channel 可以被关闭,关闭后不能再发送数据 +5. 使用 range 可以方便地遍历 channel 中的数据 + +Channel 的特性: +1. 类型安全:只能传递指定类型的数据 +2. 同步机制:无缓冲 channel 提供同步语义 +3. 异步机制:有缓冲 channel 提供异步语义 +4. 方向性:可以限制 channel 的使用方向 +5. 可关闭:发送方可以关闭 channel 通知接收方 + +Channel 类型: +1. 无缓冲 channel:make(chan T) +2. 有缓冲 channel:make(chan T, size) +3. 只发送 channel:chan<- T +4. 只接收 channel:<-chan T +5. 双向 channel:chan T + +Channel 操作: +1. 发送:ch <- value +2. 接收:value := <-ch +3. 接收并检查:value, ok := <-ch +4. 关闭:close(ch) +5. 遍历:for value := range ch + +常见模式: +1. 生产者-消费者:使用缓冲 channel 解耦生产和消费 +2. 扇出:一个输入分发到多个输出 +3. 扇入:多个输入合并到一个输出 +4. 管道:链式处理数据 +5. 工作池:固定数量的 worker 处理任务 + +高级用法: +1. 超时控制:使用 time.After +2. 非阻塞操作:使用 select 的 default 分支 +3. 心跳机制:使用 time.Ticker +4. 速率限制:控制操作频率 +5. 信号通知:使用 channel 作为信号 + +最佳实践: +1. 发送方负责关闭 channel +2. 不要从接收方关闭 channel +3. 不要关闭已关闭的 channel +4. 使用 range 遍历 channel +5. 使用 select 处理多个 channel + +注意事项: +1. 向已关闭的 channel 发送数据会 panic +2. 关闭已关闭的 channel 会 panic +3. 从已关闭的 channel 接收会得到零值 +4. nil channel 的发送和接收都会阻塞 +5. 无缓冲 channel 的发送和接收必须同时准备好 + +性能考虑: +1. 无缓冲 channel 有同步开销 +2. 有缓冲 channel 可以减少阻塞 +3. Channel 操作比直接内存访问慢 +4. 合理选择缓冲区大小 +5. 避免创建过多的 channel +*/ diff --git a/golang-learning/06-concurrency/03-select.go b/golang-learning/06-concurrency/03-select.go new file mode 100644 index 0000000..0a4bc06 --- /dev/null +++ b/golang-learning/06-concurrency/03-select.go @@ -0,0 +1,880 @@ +/* +03-select.go - Go 语言 Select 语句详解 + +学习目标: +1. 理解 select 语句的概念和作用 +2. 掌握 select 的基本语法和用法 +3. 学会使用 select 处理多个 channel +4. 了解 select 的非阻塞操作 +5. 掌握 select 的常见应用模式 + +知识点: +- select 语句的基本语法 +- select 的随机选择特性 +- default 分支的使用 +- select 与超时控制 +- select 的常见模式 +- select 的最佳实践 +*/ + +package main + +import ( + "fmt" + "math/rand" + "reflect" + "strings" + "time" +) + +func main() { + fmt.Println("=== Go 语言 Select 语句详解 ===\n") + + // 演示基本的 select 语句 + demonstrateBasicSelect() + + // 演示 select 的随机选择 + demonstrateRandomSelection() + + // 演示 select 的非阻塞操作 + demonstrateNonBlockingSelect() + + // 演示 select 的超时控制 + demonstrateSelectTimeout() + + // 演示 select 的常见模式 + demonstrateSelectPatterns() + + // 演示 select 的高级用法 + demonstrateAdvancedSelect() + + // 演示 select 的实际应用 + demonstratePracticalSelect() +} + +// demonstrateBasicSelect 演示基本的 select 语句 +func demonstrateBasicSelect() { + fmt.Println("1. 基本的 Select 语句:") + + // select 的基本概念 + fmt.Printf(" Select 的基本概念:\n") + fmt.Printf(" - 类似于 switch,但用于 channel 操作\n") + fmt.Printf(" - 可以同时等待多个 channel 操作\n") + fmt.Printf(" - 随机选择一个可执行的 case\n") + fmt.Printf(" - 如果没有 case 可执行,会阻塞等待\n") + fmt.Printf(" - default 分支提供非阻塞行为\n") + + // 基本 select 示例 + fmt.Printf(" 基本 select 示例:\n") + + ch1 := make(chan string) + ch2 := make(chan string) + + // 启动两个 goroutine 发送数据 + go func() { + time.Sleep(100 * time.Millisecond) + ch1 <- "来自 channel 1" + }() + + go func() { + time.Sleep(200 * time.Millisecond) + ch2 <- "来自 channel 2" + }() + + // 使用 select 等待任一 channel + select { + case msg1 := <-ch1: + fmt.Printf(" 接收到: %s\n", msg1) + case msg2 := <-ch2: + fmt.Printf(" 接收到: %s\n", msg2) + } + + // 接收剩余的消息 + select { + case msg1 := <-ch1: + fmt.Printf(" 接收到: %s\n", msg1) + case msg2 := <-ch2: + fmt.Printf(" 接收到: %s\n", msg2) + } + + // 多个 channel 的 select + fmt.Printf(" 多个 channel 的 select:\n") + + numbers := make(chan int) + strings := make(chan string) + booleans := make(chan bool) + + // 启动发送者 + go func() { + numbers <- 42 + strings <- "Hello" + booleans <- true + }() + + // 接收所有消息 + for i := 0; i < 3; i++ { + select { + case num := <-numbers: + fmt.Printf(" 接收到数字: %d\n", num) + case str := <-strings: + fmt.Printf(" 接收到字符串: %s\n", str) + case b := <-booleans: + fmt.Printf(" 接收到布尔值: %t\n", b) + } + } + + fmt.Println() +} + +// demonstrateRandomSelection 演示 select 的随机选择 +func demonstrateRandomSelection() { + fmt.Println("2. Select 的随机选择:") + + // 多个 case 同时就绪时的随机选择 + fmt.Printf(" 多个 case 同时就绪时的随机选择:\n") + + ch1 := make(chan string, 1) + ch2 := make(chan string, 1) + ch3 := make(chan string, 1) + + // 预先填充所有 channel + ch1 <- "Channel 1" + ch2 <- "Channel 2" + ch3 <- "Channel 3" + + // 多次执行 select,观察随机选择 + fmt.Printf(" 执行 10 次 select,观察随机选择:\n") + for i := 0; i < 10; i++ { + // 重新填充 channel + select { + case <-ch1: + case <-ch2: + case <-ch3: + } + + ch1 <- "Channel 1" + ch2 <- "Channel 2" + ch3 <- "Channel 3" + + select { + case msg := <-ch1: + fmt.Printf(" 第 %d 次: %s\n", i+1, msg) + case msg := <-ch2: + fmt.Printf(" 第 %d 次: %s\n", i+1, msg) + case msg := <-ch3: + fmt.Printf(" 第 %d 次: %s\n", i+1, msg) + } + } + + // 公平调度示例 + fmt.Printf(" 公平调度示例:\n") + + worker1 := make(chan string, 5) + worker2 := make(chan string, 5) + + // 填充任务 + for i := 1; i <= 5; i++ { + worker1 <- fmt.Sprintf("Worker1-Task%d", i) + worker2 <- fmt.Sprintf("Worker2-Task%d", i) + } + + // 公平地处理两个 worker 的任务 + for i := 0; i < 10; i++ { + select { + case task := <-worker1: + fmt.Printf(" 处理: %s\n", task) + case task := <-worker2: + fmt.Printf(" 处理: %s\n", task) + } + } + + fmt.Println() +} + +// demonstrateNonBlockingSelect 演示 select 的非阻塞操作 +func demonstrateNonBlockingSelect() { + fmt.Println("3. Select 的非阻塞操作:") + + // 使用 default 分支实现非阻塞 + fmt.Printf(" 使用 default 分支实现非阻塞:\n") + + ch := make(chan string) + + // 非阻塞接收 + select { + case msg := <-ch: + fmt.Printf(" 接收到消息: %s\n", msg) + default: + fmt.Printf(" 没有消息可接收\n") + } + + // 非阻塞发送 + select { + case ch <- "Hello": + fmt.Printf(" 消息发送成功\n") + default: + fmt.Printf(" 消息发送失败,channel 未准备好\n") + } + + // 非阻塞发送到缓冲 channel + fmt.Printf(" 非阻塞发送到缓冲 channel:\n") + + buffered := make(chan int, 2) + + // 发送到未满的缓冲 channel + for i := 1; i <= 3; i++ { + select { + case buffered <- i: + fmt.Printf(" 成功发送: %d\n", i) + default: + fmt.Printf(" 发送失败: %d (channel 已满)\n", i) + } + } + + // 非阻塞接收 + for i := 0; i < 3; i++ { + select { + case value := <-buffered: + fmt.Printf(" 接收到: %d\n", value) + default: + fmt.Printf(" 没有数据可接收\n") + } + } + + // 轮询模式 + fmt.Printf(" 轮询模式:\n") + + status := make(chan string, 1) + + // 启动状态更新器 + go func() { + statuses := []string{"初始化", "运行中", "暂停", "完成"} + for _, s := range statuses { + time.Sleep(150 * time.Millisecond) + select { + case status <- s: + default: + // 如果 channel 满了,跳过这次更新 + } + } + }() + + // 轮询状态 + for i := 0; i < 10; i++ { + select { + case s := <-status: + fmt.Printf(" 状态更新: %s\n", s) + default: + fmt.Printf(" 状态检查: 无更新\n") + } + time.Sleep(100 * time.Millisecond) + } + + fmt.Println() +} + +// demonstrateSelectTimeout 演示 select 的超时控制 +func demonstrateSelectTimeout() { + fmt.Println("4. Select 的超时控制:") + + // 基本超时控制 + fmt.Printf(" 基本超时控制:\n") + + slowCh := make(chan string) + + // 启动一个慢速响应的 goroutine + go func() { + time.Sleep(300 * time.Millisecond) + slowCh <- "慢速响应" + }() + + select { + case result := <-slowCh: + fmt.Printf(" 接收到结果: %s\n", result) + case <-time.After(200 * time.Millisecond): + fmt.Printf(" 操作超时\n") + } + + // 多级超时控制 + fmt.Printf(" 多级超时控制:\n") + + fastCh := make(chan string) + mediumCh := make(chan string) + slowCh2 := make(chan string) + + // 启动不同速度的响应 + go func() { + time.Sleep(50 * time.Millisecond) + fastCh <- "快速响应" + }() + + go func() { + time.Sleep(150 * time.Millisecond) + mediumCh <- "中速响应" + }() + + go func() { + time.Sleep(350 * time.Millisecond) + slowCh2 <- "慢速响应" + }() + + timeout1 := time.After(100 * time.Millisecond) + timeout2 := time.After(200 * time.Millisecond) + timeout3 := time.After(300 * time.Millisecond) + + for i := 0; i < 3; i++ { + select { + case result := <-fastCh: + fmt.Printf(" 快速: %s\n", result) + case result := <-mediumCh: + fmt.Printf(" 中速: %s\n", result) + case result := <-slowCh2: + fmt.Printf(" 慢速: %s\n", result) + case <-timeout1: + fmt.Printf(" 第一级超时 (100ms)\n") + timeout1 = nil // 防止重复触发 + case <-timeout2: + fmt.Printf(" 第二级超时 (200ms)\n") + timeout2 = nil + case <-timeout3: + fmt.Printf(" 第三级超时 (300ms)\n") + timeout3 = nil + } + } + + // 心跳超时检测 + fmt.Printf(" 心跳超时检测:\n") + + heartbeat := make(chan bool) + + // 启动心跳发送器 + go func() { + ticker := time.NewTicker(80 * time.Millisecond) + defer ticker.Stop() + + for i := 0; i < 5; i++ { + select { + case <-ticker.C: + heartbeat <- true + } + } + }() + + // 监控心跳 + for i := 0; i < 8; i++ { + select { + case <-heartbeat: + fmt.Printf(" 心跳正常 %d\n", i+1) + case <-time.After(100 * time.Millisecond): + fmt.Printf(" 心跳超时 %d\n", i+1) + } + } + + fmt.Println() +} + +// demonstrateSelectPatterns 演示 select 的常见模式 +func demonstrateSelectPatterns() { + fmt.Println("5. Select 的常见模式:") + + // 扇入模式 + fmt.Printf(" 扇入模式:\n") + + input1 := make(chan int) + input2 := make(chan int) + input3 := make(chan int) + + // 启动数据源 + go func() { + for i := 1; i <= 3; i++ { + input1 <- i + time.Sleep(100 * time.Millisecond) + } + close(input1) + }() + + go func() { + for i := 10; i <= 12; i++ { + input2 <- i + time.Sleep(150 * time.Millisecond) + } + close(input2) + }() + + go func() { + for i := 100; i <= 102; i++ { + input3 <- i + time.Sleep(200 * time.Millisecond) + } + close(input3) + }() + + // 扇入合并 + for { + select { + case val, ok := <-input1: + if ok { + fmt.Printf(" 来源1: %d\n", val) + } else { + input1 = nil + } + case val, ok := <-input2: + if ok { + fmt.Printf(" 来源2: %d\n", val) + } else { + input2 = nil + } + case val, ok := <-input3: + if ok { + fmt.Printf(" 来源3: %d\n", val) + } else { + input3 = nil + } + } + + // 所有 channel 都关闭时退出 + if input1 == nil && input2 == nil && input3 == nil { + break + } + } + + // 优雅关闭模式 + fmt.Printf(" 优雅关闭模式:\n") + + data := make(chan int) + done := make(chan bool) + + // 启动工作 goroutine + go func() { + defer close(data) + for i := 1; i <= 10; i++ { + select { + case data <- i: + fmt.Printf(" 发送数据: %d\n", i) + time.Sleep(50 * time.Millisecond) + case <-done: + fmt.Printf(" 接收到关闭信号,停止发送\n") + return + } + } + }() + + // 接收数据,然后发送关闭信号 + count := 0 + for value := range data { + fmt.Printf(" 接收数据: %d\n", value) + count++ + if count >= 5 { + fmt.Printf(" 发送关闭信号\n") + close(done) + } + } + + // 多路复用模式 + fmt.Printf(" 多路复用模式:\n") + + requests := make(chan Request, 5) + responses := make(chan Response, 5) + errors := make(chan error, 5) + + // 启动请求处理器 + go requestProcessor(requests, responses, errors) + + // 发送请求 + for i := 1; i <= 5; i++ { + requests <- Request{ID: i, Data: fmt.Sprintf("请求-%d", i)} + } + close(requests) + + // 处理响应和错误 + for i := 0; i < 5; i++ { + select { + case resp := <-responses: + fmt.Printf(" 响应: ID=%d, Result=%s\n", resp.ID, resp.Result) + case err := <-errors: + fmt.Printf(" 错误: %v\n", err) + } + } + + fmt.Println() +} + +// demonstrateAdvancedSelect 演示 select 的高级用法 +func demonstrateAdvancedSelect() { + fmt.Println("6. Select 的高级用法:") + + // 动态 case 选择 + fmt.Printf(" 动态 case 选择:\n") + + channels := []chan int{ + make(chan int, 1), + make(chan int, 1), + make(chan int, 1), + } + + // 填充数据 + for i, ch := range channels { + ch <- (i + 1) * 10 + } + + // 动态选择 channel + for i := 0; i < 3; i++ { + selectFromChannels(channels) + } + + // 优先级选择 + fmt.Printf(" 优先级选择:\n") + + highPriority := make(chan string, 2) + lowPriority := make(chan string, 2) + + // 填充不同优先级的任务 + highPriority <- "高优先级任务1" + lowPriority <- "低优先级任务1" + highPriority <- "高优先级任务2" + lowPriority <- "低优先级任务2" + + // 优先处理高优先级任务 + for i := 0; i < 4; i++ { + select { + case task := <-highPriority: + fmt.Printf(" 处理: %s\n", task) + default: + select { + case task := <-lowPriority: + fmt.Printf(" 处理: %s\n", task) + default: + fmt.Printf(" 没有任务\n") + } + } + } + + // 速率限制 + fmt.Printf(" 速率限制:\n") + + rateLimiter := time.NewTicker(100 * time.Millisecond) + defer rateLimiter.Stop() + + tasks := make(chan string, 5) + for i := 1; i <= 5; i++ { + tasks <- fmt.Sprintf("任务%d", i) + } + close(tasks) + + for task := range tasks { + select { + case <-rateLimiter.C: + fmt.Printf(" 执行: %s\n", task) + } + } + + // 断路器模式 + fmt.Printf(" 断路器模式:\n") + + service := make(chan string) + failures := 0 + maxFailures := 3 + + // 模拟服务调用 + go func() { + defer close(service) + for i := 1; i <= 6; i++ { + time.Sleep(50 * time.Millisecond) + if rand.Float32() < 0.5 { // 50% 失败率 + service <- fmt.Sprintf("成功响应%d", i) + } else { + service <- "ERROR" + } + } + }() + + for response := range service { + if response == "ERROR" { + failures++ + fmt.Printf(" 服务失败 (%d/%d)\n", failures, maxFailures) + if failures >= maxFailures { + fmt.Printf(" 断路器打开,停止调用服务\n") + break + } + } else { + failures = 0 // 重置失败计数 + fmt.Printf(" %s\n", response) + } + } + + fmt.Println() +} + +// demonstratePracticalSelect 演示 select 的实际应用 +func demonstratePracticalSelect() { + fmt.Println("7. Select 的实际应用:") + + // Web 服务器超时处理 + fmt.Printf(" Web 服务器超时处理:\n") + + requests := make(chan WebRequest, 3) + + // 模拟 Web 请求 + go func() { + requests <- WebRequest{ID: 1, URL: "/api/fast", ProcessTime: 50 * time.Millisecond} + requests <- WebRequest{ID: 2, URL: "/api/slow", ProcessTime: 300 * time.Millisecond} + requests <- WebRequest{ID: 3, URL: "/api/medium", ProcessTime: 150 * time.Millisecond} + close(requests) + }() + + for req := range requests { + handleWebRequest(req) + } + + // 数据库连接池 + fmt.Printf(" 数据库连接池:\n") + + connectionPool := make(chan *DBConnection, 2) + + // 初始化连接池 + for i := 1; i <= 2; i++ { + connectionPool <- &DBConnection{ID: i} + } + + // 模拟数据库操作 + for i := 1; i <= 5; i++ { + go performDBOperation(i, connectionPool) + } + + time.Sleep(500 * time.Millisecond) + + // 消息队列处理 + fmt.Printf(" 消息队列处理:\n") + + messageQueue := make(chan Message, 10) + deadLetterQueue := make(chan Message, 10) + + // 启动消息处理器 + go messageProcessor(messageQueue, deadLetterQueue) + + // 发送消息 + messages := []Message{ + {ID: 1, Content: "正常消息1", RetryCount: 0}, + {ID: 2, Content: "错误消息", RetryCount: 0}, + {ID: 3, Content: "正常消息2", RetryCount: 0}, + } + + for _, msg := range messages { + messageQueue <- msg + } + close(messageQueue) + + // 处理死信队列 + time.Sleep(200 * time.Millisecond) + close(deadLetterQueue) + + fmt.Printf(" 死信队列中的消息:\n") + for deadMsg := range deadLetterQueue { + fmt.Printf(" 死信: ID=%d, Content=%s, Retries=%d\n", + deadMsg.ID, deadMsg.Content, deadMsg.RetryCount) + } + + fmt.Println() +} + +// ========== 辅助函数和类型定义 ========== + +// Request 请求结构 +type Request struct { + ID int + Data string +} + +// Response 响应结构 +type Response struct { + ID int + Result string +} + +// requestProcessor 请求处理器 +func requestProcessor(requests <-chan Request, responses chan<- Response, errors chan<- error) { + for req := range requests { + // 模拟处理时间 + time.Sleep(50 * time.Millisecond) + + // 模拟随机错误 + if rand.Float32() < 0.2 { // 20% 错误率 + errors <- fmt.Errorf("处理请求 %d 失败", req.ID) + } else { + responses <- Response{ + ID: req.ID, + Result: fmt.Sprintf("处理完成: %s", req.Data), + } + } + } + close(responses) + close(errors) +} + +// selectFromChannels 动态选择 channel +func selectFromChannels(channels []chan int) { + // 构建 select cases + cases := make([]reflect.SelectCase, len(channels)) + for i, ch := range channels { + cases[i] = reflect.SelectCase{ + Dir: reflect.SelectRecv, + Chan: reflect.ValueOf(ch), + } + } + + // 执行 select + chosen, value, ok := reflect.Select(cases) + if ok { + fmt.Printf(" 从 channel %d 接收到: %d\n", chosen, value.Int()) + } else { + fmt.Printf(" channel %d 已关闭\n", chosen) + } +} + +// WebRequest Web 请求结构 +type WebRequest struct { + ID int + URL string + ProcessTime time.Duration +} + +// handleWebRequest 处理 Web 请求 +func handleWebRequest(req WebRequest) { + fmt.Printf(" 处理请求 %d: %s\n", req.ID, req.URL) + + result := make(chan string) + + // 启动请求处理 + go func() { + time.Sleep(req.ProcessTime) + result <- fmt.Sprintf("请求 %d 处理完成", req.ID) + }() + + // 设置超时 + select { + case response := <-result: + fmt.Printf(" %s\n", response) + case <-time.After(200 * time.Millisecond): + fmt.Printf(" 请求 %d 超时\n", req.ID) + } +} + +// DBConnection 数据库连接 +type DBConnection struct { + ID int +} + +// performDBOperation 执行数据库操作 +func performDBOperation(operationID int, pool chan *DBConnection) { + select { + case conn := <-pool: + fmt.Printf(" 操作 %d 获取连接 %d\n", operationID, conn.ID) + + // 模拟数据库操作 + time.Sleep(100 * time.Millisecond) + + fmt.Printf(" 操作 %d 完成,释放连接 %d\n", operationID, conn.ID) + pool <- conn + + case <-time.After(50 * time.Millisecond): + fmt.Printf(" 操作 %d 获取连接超时\n", operationID) + } +} + +// Message 消息结构 +type Message struct { + ID int + Content string + RetryCount int +} + +// messageProcessor 消息处理器 +func messageProcessor(messages <-chan Message, deadLetter chan<- Message) { + for msg := range messages { + fmt.Printf(" 处理消息 %d: %s\n", msg.ID, msg.Content) + + // 模拟处理 + success := !strings.Contains(msg.Content, "错误") + + if success { + fmt.Printf(" 消息 %d 处理成功\n", msg.ID) + } else { + msg.RetryCount++ + if msg.RetryCount < 3 { + fmt.Printf(" 消息 %d 处理失败,重试 %d\n", msg.ID, msg.RetryCount) + // 在实际应用中,这里会重新放入队列 + } else { + fmt.Printf(" 消息 %d 重试次数超限,放入死信队列\n", msg.ID) + deadLetter <- msg + } + } + } +} + +/* +运行这个程序: +go run 03-select.go + +学习要点: +1. Select 语句用于处理多个 channel 操作 +2. Select 会随机选择一个可执行的 case +3. Default 分支提供非阻塞行为 +4. Select 常用于超时控制和多路复用 +5. Select 是实现复杂并发模式的重要工具 + +Select 的特性: +1. 多路选择:可以同时等待多个 channel 操作 +2. 随机选择:当多个 case 同时就绪时随机选择 +3. 阻塞行为:没有 case 就绪时会阻塞等待 +4. 非阻塞:default 分支提供非阻塞行为 +5. 公平调度:避免某个 channel 被饿死 + +Select 语法: +1. 基本语法:select { case <-ch: ... } +2. 接收操作:case value := <-ch: +3. 发送操作:case ch <- value: +4. 默认分支:default: +5. 超时控制:case <-time.After(duration): + +常见模式: +1. 超时控制:使用 time.After 设置超时 +2. 非阻塞操作:使用 default 分支 +3. 扇入合并:合并多个输入源 +4. 优雅关闭:使用 done channel 通知退出 +5. 多路复用:同时处理多种类型的消息 + +高级用法: +1. 动态 case:使用 reflect.Select 动态构建 case +2. 优先级选择:嵌套 select 实现优先级 +3. 速率限制:结合 time.Ticker 控制频率 +4. 断路器:实现服务降级和熔断 +5. 负载均衡:在多个服务间分发请求 + +实际应用: +1. Web 服务器:请求超时处理 +2. 数据库:连接池管理 +3. 消息队列:消息路由和处理 +4. 微服务:服务间通信 +5. 监控系统:多源数据收集 + +最佳实践: +1. 避免在 select 中执行耗时操作 +2. 合理设置超时时间 +3. 正确处理 channel 关闭 +4. 使用 default 避免死锁 +5. 注意 select 的随机性 + +性能考虑: +1. Select 的开销比单个 channel 操作大 +2. Case 数量影响性能 +3. 随机选择有一定开销 +4. 合理使用缓冲 channel +5. 避免过度复杂的 select 结构 + +注意事项: +1. Select 中的 case 必须是 channel 操作 +2. nil channel 的 case 永远不会被选中 +3. 关闭的 channel 可以被选中 +4. Default 分支不能与其他阻塞操作共存 +5. Select 语句本身不是循环 +*/ diff --git a/golang-learning/06-concurrency/04-sync-package.go b/golang-learning/06-concurrency/04-sync-package.go new file mode 100644 index 0000000..06a15ee --- /dev/null +++ b/golang-learning/06-concurrency/04-sync-package.go @@ -0,0 +1,1183 @@ +/* +04-sync-package.go - Go 语言 Sync 包详解 + +学习目标: +1. 理解 sync 包的作用和重要性 +2. 掌握 Mutex 和 RWMutex 的使用 +3. 学会使用 WaitGroup 进行同步 +4. 了解 Once 的使用场景 +5. 掌握 Cond 条件变量的用法 + +知识点: +- sync.Mutex 互斥锁 +- sync.RWMutex 读写锁 +- sync.WaitGroup 等待组 +- sync.Once 单次执行 +- sync.Cond 条件变量 +- sync.Pool 对象池 +- 原子操作 sync/atomic +*/ + +package main + +import ( + "fmt" + "math" + "math/rand" + "strings" + "sync" + "sync/atomic" + "time" + "unsafe" +) + +func main() { + fmt.Println("=== Go 语言 Sync 包详解 ===\\n") + + // 演示 Mutex 互斥锁 + demonstrateMutex() + + // 演示 RWMutex 读写锁 + demonstrateRWMutex() + + // 演示 WaitGroup 等待组 + demonstrateWaitGroup() + + // 演示 Once 单次执行 + demonstrateOnce() + + // 演示 Cond 条件变量 + demonstrateCond() + + // 演示 Pool 对象池 + demonstratePool() + + // 演示原子操作 + demonstrateAtomic() +} + +// demonstrateMutex 演示 Mutex 互斥锁 +func demonstrateMutex() { + fmt.Println("1. Mutex 互斥锁:") + + // Mutex 的基本概念 + fmt.Printf(" Mutex 的基本概念:\\n") + fmt.Printf(" - 互斥锁,同时只允许一个 goroutine 访问共享资源\\n") + fmt.Printf(" - 用于保护临界区,防止竞态条件\\n") + fmt.Printf(" - Lock() 获取锁,Unlock() 释放锁\\n") + fmt.Printf(" - 零值可以直接使用\\n") + fmt.Printf(" - 不可重入,同一 goroutine 不能重复加锁\\n") + + // 不使用锁的竞态条件示例 + fmt.Printf(" 不使用锁的竞态条件示例:\\n") + + var unsafeCounter int + var wg sync.WaitGroup + + // 启动多个 goroutine 增加计数器 + for i := 0; i < 10; i++ { + wg.Add(1) + go func(id int) { + defer wg.Done() + for j := 0; j < 1000; j++ { + unsafeCounter++ // 竞态条件 + } + }(i) + } + + wg.Wait() + fmt.Printf(" 不安全计数器最终值: %d (期望: 10000)\\n", unsafeCounter) + + // 使用 Mutex 保护共享资源 + fmt.Printf(" 使用 Mutex 保护共享资源:\\n") + + safeCounter := &SafeCounter{} + + // 启动多个 goroutine 安全地增加计数器 + for i := 0; i < 10; i++ { + wg.Add(1) + go func(id int) { + defer wg.Done() + for j := 0; j < 1000; j++ { + safeCounter.Increment() + } + }(i) + } + + wg.Wait() + fmt.Printf(" 安全计数器最终值: %d\\n", safeCounter.Value()) + + // 银行账户转账示例 + fmt.Printf(" 银行账户转账示例:\\n") + + account1 := NewBankAccount("Alice", 1000) + account2 := NewBankAccount("Bob", 500) + + fmt.Printf(" 转账前: %s\\n", account1.String()) + fmt.Printf(" 转账前: %s\\n", account2.String()) + + // 并发转账 + for i := 0; i < 5; i++ { + wg.Add(2) + + go func() { + defer wg.Done() + Transfer(account1, account2, 50) + }() + + go func() { + defer wg.Done() + Transfer(account2, account1, 30) + }() + } + + wg.Wait() + + fmt.Printf(" 转账后: %s\\n", account1.String()) + fmt.Printf(" 转账后: %s\\n", account2.String()) + fmt.Printf(" 总金额: %.2f (应该保持不变)\\n", + account1.Balance()+account2.Balance()) + + fmt.Println() +} + +// demonstrateRWMutex 演示 RWMutex 读写锁 +func demonstrateRWMutex() { + fmt.Println("2. RWMutex 读写锁:") + + // RWMutex 的基本概念 + fmt.Printf(" RWMutex 的基本概念:\\n") + fmt.Printf(" - 读写锁,允许多个读者或一个写者\\n") + fmt.Printf(" - RLock()/RUnlock() 用于读操作\\n") + fmt.Printf(" - Lock()/Unlock() 用于写操作\\n") + fmt.Printf(" - 读操作可以并发,写操作互斥\\n") + fmt.Printf(" - 适用于读多写少的场景\\n") + + // 配置管理示例 + fmt.Printf(" 配置管理示例:\\n") + + config := NewConfig() + + // 设置初始配置 + config.Set("database_url", "localhost:5432") + config.Set("max_connections", "100") + config.Set("timeout", "30s") + + var wg sync.WaitGroup + + // 启动多个读者 + for i := 0; i < 10; i++ { + wg.Add(1) + go func(id int) { + defer wg.Done() + for j := 0; j < 5; j++ { + url := config.Get("database_url") + fmt.Printf(" 读者 %d: database_url = %s\\n", id, url) + time.Sleep(10 * time.Millisecond) + } + }(i) + } + + // 启动少量写者 + for i := 0; i < 2; i++ { + wg.Add(1) + go func(id int) { + defer wg.Done() + time.Sleep(50 * time.Millisecond) + newURL := fmt.Sprintf("server%d:5432", id) + config.Set("database_url", newURL) + fmt.Printf(" 写者 %d: 更新 database_url = %s\\n", id, newURL) + }(i) + } + + wg.Wait() + + // 缓存系统示例 + fmt.Printf(" 缓存系统示例:\\n") + + cache := NewCache() + + // 预填充缓存 + cache.Set("user:1", "Alice") + cache.Set("user:2", "Bob") + cache.Set("user:3", "Charlie") + + // 并发读写测试 + for i := 0; i < 5; i++ { + wg.Add(2) + + // 读操作 + go func(id int) { + defer wg.Done() + key := fmt.Sprintf("user:%d", (id%3)+1) + if value, ok := cache.Get(key); ok { + fmt.Printf(" 缓存读取: %s = %s\\n", key, value) + } + }(i) + + // 写操作 + go func(id int) { + defer wg.Done() + key := fmt.Sprintf("user:%d", id+4) + value := fmt.Sprintf("User%d", id+4) + cache.Set(key, value) + fmt.Printf(" 缓存写入: %s = %s\\n", key, value) + }(i) + } + + wg.Wait() + + fmt.Printf(" 缓存大小: %d\\n", cache.Size()) + + fmt.Println() +} + +// demonstrateWaitGroup 演示 WaitGroup 等待组 +func demonstrateWaitGroup() { + fmt.Println("3. WaitGroup 等待组:") + + // WaitGroup 的基本概念 + fmt.Printf(" WaitGroup 的基本概念:\\n") + fmt.Printf(" - 用于等待一组 goroutine 完成\\n") + fmt.Printf(" - Add(n) 增加等待计数\\n") + fmt.Printf(" - Done() 减少等待计数\\n") + fmt.Printf(" - Wait() 阻塞直到计数为零\\n") + fmt.Printf(" - 零值可以直接使用\\n") + + // 基本使用示例 + fmt.Printf(" 基本使用示例:\\n") + + var wg sync.WaitGroup + + // 启动多个工作 goroutine + for i := 1; i <= 5; i++ { + wg.Add(1) + go func(id int) { + defer wg.Done() + fmt.Printf(" 工作者 %d 开始工作\\n", id) + time.Sleep(time.Duration(rand.Intn(200)) * time.Millisecond) + fmt.Printf(" 工作者 %d 完成工作\\n", id) + }(i) + } + + fmt.Printf(" 等待所有工作者完成...\\n") + wg.Wait() + fmt.Printf(" 所有工作者已完成\\n") + + // 批量处理示例 + fmt.Printf(" 批量处理示例:\\n") + + urls := []string{ + "https://api.example.com/users", + "https://api.example.com/orders", + "https://api.example.com/products", + "https://api.example.com/categories", + "https://api.example.com/reviews", + } + + results := make([]string, len(urls)) + + for i, url := range urls { + wg.Add(1) + go func(index int, endpoint string) { + defer wg.Done() + result := fetchData(endpoint) + results[index] = result + }(i, url) + } + + wg.Wait() + + fmt.Printf(" 批量处理结果:\\n") + for i, result := range results { + fmt.Printf(" %s: %s\\n", urls[i], result) + } + + // 分阶段处理示例 + fmt.Printf(" 分阶段处理示例:\\n") + + // 第一阶段:数据准备 + fmt.Printf(" 第一阶段:数据准备\\n") + dataChannels := make([]chan int, 3) + for i := range dataChannels { + dataChannels[i] = make(chan int, 10) + wg.Add(1) + go func(id int, ch chan int) { + defer wg.Done() + defer close(ch) + for j := 1; j <= 5; j++ { + ch <- id*10 + j + time.Sleep(20 * time.Millisecond) + } + fmt.Printf(" 数据源 %d 准备完成\\n", id) + }(i, dataChannels[i]) + } + + wg.Wait() + fmt.Printf(" 第一阶段完成\\n") + + // 第二阶段:数据处理 + fmt.Printf(" 第二阶段:数据处理\\n") + processedData := make([][]int, len(dataChannels)) + + for i, ch := range dataChannels { + wg.Add(1) + go func(id int, dataCh chan int) { + defer wg.Done() + var processed []int + for data := range dataCh { + processed = append(processed, data*2) + } + processedData[id] = processed + fmt.Printf(" 处理器 %d 完成\\n", id) + }(i, ch) + } + + wg.Wait() + fmt.Printf(" 第二阶段完成\\n") + + // 输出最终结果 + for i, data := range processedData { + fmt.Printf(" 处理器 %d 结果: %v\\n", i, data) + } + + fmt.Println() +} + +// demonstrateOnce 演示 Once 单次执行 +func demonstrateOnce() { + fmt.Println("4. Once 单次执行:") + + // Once 的基本概念 + fmt.Printf(" Once 的基本概念:\\n") + fmt.Printf(" - 确保函数只执行一次\\n") + fmt.Printf(" - 线程安全的单例模式实现\\n") + fmt.Printf(" - Do(func()) 方法执行函数\\n") + fmt.Printf(" - 常用于初始化操作\\n") + fmt.Printf(" - 零值可以直接使用\\n") + + // 基本使用示例 + fmt.Printf(" 基本使用示例:\\n") + + var once sync.Once + var wg sync.WaitGroup + + // 启动多个 goroutine 尝试执行初始化 + for i := 1; i <= 5; i++ { + wg.Add(1) + go func(id int) { + defer wg.Done() + once.Do(func() { + fmt.Printf(" 初始化操作执行 (来自 goroutine %d)\\n", id) + time.Sleep(100 * time.Millisecond) + fmt.Printf(" 初始化操作完成\\n") + }) + fmt.Printf(" Goroutine %d 继续执行\\n", id) + }(i) + } + + wg.Wait() + + // 单例模式示例 + fmt.Printf(" 单例模式示例:\\n") + + // 并发获取单例实例 + for i := 1; i <= 5; i++ { + wg.Add(1) + go func(id int) { + defer wg.Done() + instance := GetDatabaseInstance() + fmt.Printf(" Goroutine %d 获取实例: %p\\n", id, instance) + }(i) + } + + wg.Wait() + + // 配置加载示例 + fmt.Printf(" 配置加载示例:\\n") + + configLoader := &ConfigLoader{} + + // 多个 goroutine 同时加载配置 + for i := 1; i <= 3; i++ { + wg.Add(1) + go func(id int) { + defer wg.Done() + config := configLoader.GetConfig() + fmt.Printf(" Goroutine %d 获取配置: %v\\n", id, config) + }(i) + } + + wg.Wait() + + // 资源初始化示例 + fmt.Printf(" 资源初始化示例:\\n") + + resource := &ExpensiveResource{} + + // 多个 goroutine 使用资源 + for i := 1; i <= 4; i++ { + wg.Add(1) + go func(id int) { + defer wg.Done() + result := resource.Process(fmt.Sprintf("数据-%d", id)) + fmt.Printf(" Goroutine %d 处理结果: %s\\n", id, result) + }(i) + } + + wg.Wait() + + fmt.Println() +} + +// demonstrateCond 演示 Cond 条件变量 +func demonstrateCond() { + fmt.Println("5. Cond 条件变量:") + + // Cond 的基本概念 + fmt.Printf(" Cond 的基本概念:\\n") + fmt.Printf(" - 条件变量,用于等待或通知条件变化\\n") + fmt.Printf(" - 必须与 Mutex 或 RWMutex 配合使用\\n") + fmt.Printf(" - Wait() 等待条件满足\\n") + fmt.Printf(" - Signal() 唤醒一个等待者\\n") + fmt.Printf(" - Broadcast() 唤醒所有等待者\\n") + + // 生产者-消费者示例 + fmt.Printf(" 生产者-消费者示例:\\n") + + buffer := &Buffer{ + items: make([]int, 0, 5), + cond: sync.NewCond(&sync.Mutex{}), + } + + var wg sync.WaitGroup + + // 启动消费者 + for i := 1; i <= 2; i++ { + wg.Add(1) + go func(id int) { + defer wg.Done() + for j := 0; j < 5; j++ { + item := buffer.Consume() + fmt.Printf(" 消费者 %d 消费: %d\\n", id, item) + time.Sleep(150 * time.Millisecond) + } + }(i) + } + + // 启动生产者 + for i := 1; i <= 2; i++ { + wg.Add(1) + go func(id int) { + defer wg.Done() + for j := 1; j <= 5; j++ { + item := id*10 + j + buffer.Produce(item) + fmt.Printf(" 生产者 %d 生产: %d\\n", id, item) + time.Sleep(100 * time.Millisecond) + } + }(i) + } + + wg.Wait() + + // 任务队列示例 + fmt.Printf(" 任务队列示例:\\n") + + taskQueue := &TaskQueue{ + tasks: make([]Task, 0), + cond: sync.NewCond(&sync.Mutex{}), + } + + // 启动工作者 + for i := 1; i <= 3; i++ { + wg.Add(1) + go func(id int) { + defer wg.Done() + for j := 0; j < 3; j++ { + task := taskQueue.GetTask() + fmt.Printf(" 工作者 %d 执行任务: %s\\n", id, task.Name) + time.Sleep(100 * time.Millisecond) + } + }(i) + } + + // 添加任务 + go func() { + tasks := []Task{ + {Name: "任务A"}, {Name: "任务B"}, {Name: "任务C"}, + {Name: "任务D"}, {Name: "任务E"}, {Name: "任务F"}, + {Name: "任务G"}, {Name: "任务H"}, {Name: "任务I"}, + } + + for _, task := range tasks { + taskQueue.AddTask(task) + time.Sleep(50 * time.Millisecond) + } + }() + + wg.Wait() + + fmt.Println() +} + +// demonstratePool 演示 Pool 对象池 +func demonstratePool() { + fmt.Println("6. Pool 对象池:") + + // Pool 的基本概念 + fmt.Printf(" Pool 的基本概念:\\n") + fmt.Printf(" - 对象池,用于复用对象减少 GC 压力\\n") + fmt.Printf(" - Get() 获取对象,Put() 归还对象\\n") + fmt.Printf(" - New 字段定义创建新对象的函数\\n") + fmt.Printf(" - 线程安全,可以并发使用\\n") + fmt.Printf(" - 适用于频繁创建销毁的对象\\n") + + // 基本使用示例 + fmt.Printf(" 基本使用示例:\\n") + + // 创建字符串构建器池 + builderPool := &sync.Pool{ + New: func() interface{} { + fmt.Printf(" 创建新的 StringBuilder\\n") + return &StringBuilder{data: make([]string, 0, 10)} + }, + } + + var wg sync.WaitGroup + + // 并发使用对象池 + for i := 1; i <= 5; i++ { + wg.Add(1) + go func(id int) { + defer wg.Done() + + // 从池中获取对象 + builder := builderPool.Get().(*StringBuilder) + + // 使用对象 + builder.Append(fmt.Sprintf("Goroutine-%d", id)) + builder.Append("处理数据") + result := builder.String() + + fmt.Printf(" Goroutine %d 结果: %s\\n", id, result) + + // 重置对象状态 + builder.Reset() + + // 归还对象到池中 + builderPool.Put(builder) + }(i) + } + + wg.Wait() + + // 缓冲区池示例 + fmt.Printf(" 缓冲区池示例:\\n") + + bufferPool := &sync.Pool{ + New: func() interface{} { + fmt.Printf(" 创建新的缓冲区\\n") + return make([]byte, 1024) + }, + } + + // 模拟网络请求处理 + for i := 1; i <= 3; i++ { + wg.Add(1) + go func(id int) { + defer wg.Done() + + // 获取缓冲区 + buffer := bufferPool.Get().([]byte) + + // 模拟数据处理 + data := fmt.Sprintf("请求 %d 的数据", id) + copy(buffer, data) + + fmt.Printf(" 处理请求 %d: %s\\n", id, string(buffer[:len(data)])) + + // 清理缓冲区 + for i := range buffer { + buffer[i] = 0 + } + + // 归还缓冲区 + bufferPool.Put(buffer) + }(i) + } + + wg.Wait() + + // 连接池示例 + fmt.Printf(" 连接池示例:\\n") + + connPool := &ConnectionPool{ + pool: &sync.Pool{ + New: func() interface{} { + fmt.Printf(" 创建新的数据库连接\\n") + return &DBConn{ID: rand.Intn(1000)} + }, + }, + } + + // 并发使用连接 + for i := 1; i <= 4; i++ { + wg.Add(1) + go func(id int) { + defer wg.Done() + + conn := connPool.GetConnection() + fmt.Printf(" Goroutine %d 使用连接 %d\\n", id, conn.ID) + + // 模拟数据库操作 + time.Sleep(100 * time.Millisecond) + + connPool.PutConnection(conn) + }(i) + } + + wg.Wait() + + fmt.Println() +} + +// demonstrateAtomic 演示原子操作 +func demonstrateAtomic() { + fmt.Println("7. 原子操作:") + + // 原子操作的基本概念 + fmt.Printf(" 原子操作的基本概念:\\n") + fmt.Printf(" - 不可分割的操作,要么全部完成要么全部不完成\\n") + fmt.Printf(" - 无需加锁即可保证并发安全\\n") + fmt.Printf(" - 性能比互斥锁更好\\n") + fmt.Printf(" - 适用于简单的数值操作\\n") + fmt.Printf(" - sync/atomic 包提供原子操作函数\\n") + + // 原子计数器示例 + fmt.Printf(" 原子计数器示例:\\n") + + var atomicCounter int64 + var wg sync.WaitGroup + + // 启动多个 goroutine 原子地增加计数器 + for i := 0; i < 10; i++ { + wg.Add(1) + go func(id int) { + defer wg.Done() + for j := 0; j < 1000; j++ { + atomic.AddInt64(&atomicCounter, 1) + } + }(i) + } + + wg.Wait() + fmt.Printf(" 原子计数器最终值: %d\\n", atomic.LoadInt64(&atomicCounter)) + + // 原子操作类型示例 + fmt.Printf(" 原子操作类型示例:\\n") + + var ( + intVal int64 = 100 + uintVal uint64 = 200 + floatVal uint64 // 存储 float64 的位表示 + boolVal int32 // 存储 bool 值 + stringPtr unsafe.Pointer + ) + + // 整数原子操作 + atomic.AddInt64(&intVal, 50) + fmt.Printf(" 整数加法: %d\\n", atomic.LoadInt64(&intVal)) + + old := atomic.SwapInt64(&intVal, 300) + fmt.Printf(" 整数交换: 旧值=%d, 新值=%d\\n", old, atomic.LoadInt64(&intVal)) + + // 比较并交换 + swapped := atomic.CompareAndSwapInt64(&intVal, 300, 400) + fmt.Printf(" 比较并交换: 成功=%t, 当前值=%d\\n", swapped, atomic.LoadInt64(&intVal)) + + // 无符号整数操作 + atomic.AddUint64(&uintVal, 100) + fmt.Printf(" 无符号整数: %d\\n", atomic.LoadUint64(&uintVal)) + + // 浮点数操作(通过位操作) + f := 3.14159 + atomic.StoreUint64(&floatVal, math.Float64bits(f)) + loadedFloat := math.Float64frombits(atomic.LoadUint64(&floatVal)) + fmt.Printf(" 浮点数: %.5f\\n", loadedFloat) + + // 布尔值操作 + atomic.StoreInt32(&boolVal, 1) // true + fmt.Printf(" 布尔值: %t\\n", atomic.LoadInt32(&boolVal) != 0) + + // 指针操作 + str1 := "Hello" + str2 := "World" + atomic.StorePointer(&stringPtr, unsafe.Pointer(&str1)) + loadedStr := (*string)(atomic.LoadPointer(&stringPtr)) + fmt.Printf(" 指针字符串: %s\\n", *loadedStr) + + atomic.StorePointer(&stringPtr, unsafe.Pointer(&str2)) + loadedStr = (*string)(atomic.LoadPointer(&stringPtr)) + fmt.Printf(" 指针字符串: %s\\n", *loadedStr) + + // 原子值示例 + fmt.Printf(" 原子值示例:\\n") + + var atomicValue atomic.Value + + // 存储不同类型的值 + atomicValue.Store("字符串值") + fmt.Printf(" 原子值: %v\\n", atomicValue.Load()) + + atomicValue.Store(42) + fmt.Printf(" 原子值: %v\\n", atomicValue.Load()) + + atomicValue.Store(map[string]int{"key": 100}) + fmt.Printf(" 原子值: %v\\n", atomicValue.Load()) + + // 性能对比示例 + fmt.Printf(" 性能对比示例:\\n") + + // 使用原子操作的计数器 + atomicStats := &AtomicStats{} + start := time.Now() + + for i := 0; i < 10; i++ { + wg.Add(1) + go func() { + defer wg.Done() + for j := 0; j < 10000; j++ { + atomicStats.Increment() + } + }() + } + wg.Wait() + + atomicDuration := time.Since(start) + fmt.Printf(" 原子操作耗时: %v, 结果: %d\\n", + atomicDuration, atomicStats.Value()) + + // 使用互斥锁的计数器 + mutexStats := &MutexStats{} + start = time.Now() + + for i := 0; i < 10; i++ { + wg.Add(1) + go func() { + defer wg.Done() + for j := 0; j < 10000; j++ { + mutexStats.Increment() + } + }() + } + wg.Wait() + + mutexDuration := time.Since(start) + fmt.Printf(" 互斥锁耗时: %v, 结果: %d\\n", + mutexDuration, mutexStats.Value()) + + fmt.Printf(" 性能提升: %.2fx\\n", + float64(mutexDuration)/float64(atomicDuration)) + + fmt.Println() +} + +// ========== 类型定义和辅助函数 ========== + +// SafeCounter 线程安全的计数器 +type SafeCounter struct { + mu sync.Mutex + value int +} + +func (c *SafeCounter) Increment() { + c.mu.Lock() + defer c.mu.Unlock() + c.value++ +} + +func (c *SafeCounter) Value() int { + c.mu.Lock() + defer c.mu.Unlock() + return c.value +} + +// BankAccount 银行账户 +type BankAccount struct { + mu sync.Mutex + name string + balance float64 +} + +func NewBankAccount(name string, balance float64) *BankAccount { + return &BankAccount{ + name: name, + balance: balance, + } +} + +func (a *BankAccount) Deposit(amount float64) { + a.mu.Lock() + defer a.mu.Unlock() + a.balance += amount +} + +func (a *BankAccount) Withdraw(amount float64) bool { + a.mu.Lock() + defer a.mu.Unlock() + if a.balance >= amount { + a.balance -= amount + return true + } + return false +} + +func (a *BankAccount) Balance() float64 { + a.mu.Lock() + defer a.mu.Unlock() + return a.balance +} + +func (a *BankAccount) String() string { + a.mu.Lock() + defer a.mu.Unlock() + return fmt.Sprintf("%s: $%.2f", a.name, a.balance) +} + +// Transfer 转账函数 +func Transfer(from, to *BankAccount, amount float64) { + // 避免死锁:总是按照相同的顺序获取锁 + if from == to { + return + } + + // 使用地址比较确保锁的顺序 + if uintptr(unsafe.Pointer(from)) < uintptr(unsafe.Pointer(to)) { + from.mu.Lock() + defer from.mu.Unlock() + to.mu.Lock() + defer to.mu.Unlock() + } else { + to.mu.Lock() + defer to.mu.Unlock() + from.mu.Lock() + defer from.mu.Unlock() + } + + if from.balance >= amount { + from.balance -= amount + to.balance += amount + } +} + +// Config 配置管理器 +type Config struct { + mu sync.RWMutex + data map[string]string +} + +func NewConfig() *Config { + return &Config{ + data: make(map[string]string), + } +} + +func (c *Config) Set(key, value string) { + c.mu.Lock() + defer c.mu.Unlock() + c.data[key] = value +} + +func (c *Config) Get(key string) string { + c.mu.RLock() + defer c.mu.RUnlock() + return c.data[key] +} + +// Cache 缓存系统 +type Cache struct { + mu sync.RWMutex + data map[string]string +} + +func NewCache() *Cache { + return &Cache{ + data: make(map[string]string), + } +} + +func (c *Cache) Set(key, value string) { + c.mu.Lock() + defer c.mu.Unlock() + c.data[key] = value +} + +func (c *Cache) Get(key string) (string, bool) { + c.mu.RLock() + defer c.mu.RUnlock() + value, ok := c.data[key] + return value, ok +} + +func (c *Cache) Size() int { + c.mu.RLock() + defer c.mu.RUnlock() + return len(c.data) +} + +// fetchData 模拟数据获取 +func fetchData(url string) string { + time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond) + return fmt.Sprintf("数据来自 %s", url) +} + +// 单例模式相关 +var ( + dbInstance *Database + dbOnce sync.Once +) + +type Database struct { + connectionString string +} + +func GetDatabaseInstance() *Database { + dbOnce.Do(func() { + fmt.Printf(" 创建数据库实例\\n") + time.Sleep(100 * time.Millisecond) // 模拟初始化时间 + dbInstance = &Database{ + connectionString: "localhost:5432", + } + }) + return dbInstance +} + +// ConfigLoader 配置加载器 +type ConfigLoader struct { + once sync.Once + config map[string]string +} + +func (cl *ConfigLoader) GetConfig() map[string]string { + cl.once.Do(func() { + fmt.Printf(" 加载配置文件\\n") + time.Sleep(50 * time.Millisecond) + cl.config = map[string]string{ + "database_url": "localhost:5432", + "redis_url": "localhost:6379", + "log_level": "info", + } + }) + return cl.config +} + +// ExpensiveResource 昂贵资源 +type ExpensiveResource struct { + once sync.Once + initialized bool + data []string +} + +func (er *ExpensiveResource) init() { + fmt.Printf(" 初始化昂贵资源\\n") + time.Sleep(200 * time.Millisecond) + er.data = []string{"资源1", "资源2", "资源3"} + er.initialized = true +} + +func (er *ExpensiveResource) Process(input string) string { + er.once.Do(er.init) + return fmt.Sprintf("处理 %s 使用 %v", input, er.data) +} + +// Buffer 缓冲区(生产者-消费者) +type Buffer struct { + mu sync.Mutex + cond *sync.Cond + items []int + size int +} + +func (b *Buffer) Produce(item int) { + b.cond.L.Lock() + defer b.cond.L.Unlock() + + // 等待缓冲区有空间 + for len(b.items) >= 5 { + b.cond.Wait() + } + + b.items = append(b.items, item) + b.cond.Signal() // 通知消费者 +} + +func (b *Buffer) Consume() int { + b.cond.L.Lock() + defer b.cond.L.Unlock() + + // 等待缓冲区有数据 + for len(b.items) == 0 { + b.cond.Wait() + } + + item := b.items[0] + b.items = b.items[1:] + b.cond.Signal() // 通知生产者 + return item +} + +// Task 任务 +type Task struct { + Name string +} + +// TaskQueue 任务队列 +type TaskQueue struct { + mu sync.Mutex + cond *sync.Cond + tasks []Task +} + +func (tq *TaskQueue) AddTask(task Task) { + tq.cond.L.Lock() + defer tq.cond.L.Unlock() + + tq.tasks = append(tq.tasks, task) + tq.cond.Signal() // 通知等待的工作者 +} + +func (tq *TaskQueue) GetTask() Task { + tq.cond.L.Lock() + defer tq.cond.L.Unlock() + + // 等待任务可用 + for len(tq.tasks) == 0 { + tq.cond.Wait() + } + + task := tq.tasks[0] + tq.tasks = tq.tasks[1:] + return task +} + +// StringBuilder 字符串构建器 +type StringBuilder struct { + data []string +} + +func (sb *StringBuilder) Append(s string) { + sb.data = append(sb.data, s) +} + +func (sb *StringBuilder) String() string { + return strings.Join(sb.data, " ") +} + +func (sb *StringBuilder) Reset() { + sb.data = sb.data[:0] +} + +// ConnectionPool 连接池 +type ConnectionPool struct { + pool *sync.Pool +} + +type DBConn struct { + ID int +} + +func (cp *ConnectionPool) GetConnection() *DBConn { + return cp.pool.Get().(*DBConn) +} + +func (cp *ConnectionPool) PutConnection(conn *DBConn) { + cp.pool.Put(conn) +} + +// AtomicStats 原子统计 +type AtomicStats struct { + counter int64 +} + +func (as *AtomicStats) Increment() { + atomic.AddInt64(&as.counter, 1) +} + +func (as *AtomicStats) Value() int64 { + return atomic.LoadInt64(&as.counter) +} + +// MutexStats 互斥锁统计 +type MutexStats struct { + mu sync.Mutex + counter int64 +} + +func (ms *MutexStats) Increment() { + ms.mu.Lock() + defer ms.mu.Unlock() + ms.counter++ +} + +func (ms *MutexStats) Value() int64 { + ms.mu.Lock() + defer ms.mu.Unlock() + return ms.counter +} + +/* +运行这个程序: +go run 04-sync-package.go + +学习要点: +1. sync 包提供了多种同步原语 +2. Mutex 用于互斥访问,RWMutex 适用于读多写少 +3. WaitGroup 用于等待一组 goroutine 完成 +4. Once 确保函数只执行一次 +5. Cond 用于条件等待和通知 + +Sync 包组件: +1. Mutex:互斥锁,同时只允许一个 goroutine 访问 +2. RWMutex:读写锁,允许多个读者或一个写者 +3. WaitGroup:等待组,等待一组 goroutine 完成 +4. Once:单次执行,确保函数只执行一次 +5. Cond:条件变量,用于等待条件变化 +6. Pool:对象池,复用对象减少 GC 压力 + +使用场景: +1. Mutex:保护共享资源,防止竞态条件 +2. RWMutex:读多写少的场景,如配置管理、缓存 +3. WaitGroup:批量处理、分阶段处理 +4. Once:单例模式、资源初始化 +5. Cond:生产者-消费者、任务队列 +6. Pool:频繁创建销毁的对象 + +原子操作: +1. 无锁操作,性能更好 +2. 适用于简单的数值操作 +3. 支持整数、指针、布尔值等类型 +4. 提供加法、交换、比较并交换等操作 +5. atomic.Value 支持任意类型 + +最佳实践: +1. 优先使用 channel 进行通信 +2. 必要时使用 sync 包的同步原语 +3. 避免死锁,注意锁的顺序 +4. 使用 defer 确保锁被释放 +5. 合理选择同步机制 + +性能考虑: +1. 原子操作 > RWMutex > Mutex > Channel +2. 读写锁适用于读多写少 +3. 对象池可以减少 GC 压力 +4. 避免锁竞争和锁粒度过大 +5. 合理使用缓冲区 + +注意事项: +1. 不要复制包含锁的结构体 +2. 避免在持有锁时调用可能阻塞的操作 +3. 注意死锁的产生条件 +4. Cond 必须与锁配合使用 +5. Pool 中的对象可能被 GC 回收 +*/ diff --git a/golang-learning/06-concurrency/05-worker-pools.go b/golang-learning/06-concurrency/05-worker-pools.go new file mode 100644 index 0000000..565e738 --- /dev/null +++ b/golang-learning/06-concurrency/05-worker-pools.go @@ -0,0 +1,1561 @@ +/* +05-worker-pools.go - Go 语言工作池模式详解 + +学习目标: +1. 理解工作池模式的概念和优势 +2. 掌握固定大小工作池的实现 +3. 学会动态工作池的设计 +4. 了解工作池的优雅关闭 +5. 掌握工作池的实际应用场景 + +知识点: +- 工作池模式的基本概念 +- 固定大小工作池 +- 动态工作池 +- 工作池的生命周期管理 +- 错误处理和监控 +- 性能优化技巧 +*/ + +package main + +import ( + "context" + "fmt" + "math/rand" + "runtime" + "sync" + "time" +) + +func main() { + fmt.Println("=== Go 语言工作池模式详解 ===\\n") + + // 演示基本工作池 + demonstrateBasicWorkerPool() + + // 演示缓冲工作池 + demonstrateBufferedWorkerPool() + + // 演示动态工作池 + demonstrateDynamicWorkerPool() + + // 演示带上下文的工作池 + demonstrateContextWorkerPool() + + // 演示工作池的错误处理 + demonstrateErrorHandling() + + // 演示工作池的监控 + demonstrateWorkerPoolMonitoring() + + // 演示实际应用场景 + demonstratePracticalApplications() +} + +// demonstrateBasicWorkerPool 演示基本工作池 +func demonstrateBasicWorkerPool() { + fmt.Println("1. 基本工作池:") + + // 工作池的基本概念 + fmt.Printf(" 工作池的基本概念:\\n") + fmt.Printf(" - 预先创建固定数量的工作 goroutine\\n") + fmt.Printf(" - 通过 channel 分发任务给工作者\\n") + fmt.Printf(" - 控制并发数量,避免创建过多 goroutine\\n") + fmt.Printf(" - 提高资源利用率和系统稳定性\\n") + fmt.Printf(" - 适用于任务数量大且不确定的场景\\n") + + // 基本工作池示例 + fmt.Printf(" 基本工作池示例:\\n") + + const numWorkers = 3 + const numJobs = 10 + + jobs := make(chan Job, numJobs) + results := make(chan Result, numJobs) + + // 启动工作者 + for w := 1; w <= numWorkers; w++ { + go worker(w, jobs, results) + } + + // 发送任务 + for j := 1; j <= numJobs; j++ { + jobs <- Job{ + ID: j, + Data: fmt.Sprintf("任务数据-%d", j), + } + } + close(jobs) + + // 收集结果 + for r := 1; r <= numJobs; r++ { + result := <-results + fmt.Printf(" %s\\n", result.Message) + } + + // 简化的工作池实现 + fmt.Printf(" 简化的工作池实现:\\n") + + simplePool := NewSimpleWorkerPool(4) + simplePool.Start() + + // 提交任务 + for i := 1; i <= 8; i++ { + taskID := i + simplePool.Submit(func() { + fmt.Printf(" 执行简单任务 %d\\n", taskID) + time.Sleep(100 * time.Millisecond) + }) + } + + simplePool.Stop() + + fmt.Println() +} + +// demonstrateBufferedWorkerPool 演示缓冲工作池 +func demonstrateBufferedWorkerPool() { + fmt.Println("2. 缓冲工作池:") + + // 缓冲工作池的优势 + fmt.Printf(" 缓冲工作池的优势:\\n") + fmt.Printf(" - 任务队列缓冲,减少阻塞\\n") + fmt.Printf(" - 平滑处理突发任务\\n") + fmt.Printf(" - 提高系统吞吐量\\n") + fmt.Printf(" - 更好的负载均衡\\n") + + // 缓冲工作池示例 + fmt.Printf(" 缓冲工作池示例:\\n") + + bufferedPool := NewBufferedWorkerPool(3, 10) // 3个工作者,10个缓冲 + bufferedPool.Start() + + // 快速提交大量任务 + for i := 1; i <= 15; i++ { + taskID := i + success := bufferedPool.TrySubmit(func() { + fmt.Printf(" 缓冲任务 %d 执行\\n", taskID) + time.Sleep(50 * time.Millisecond) + }) + + if !success { + fmt.Printf(" 任务 %d 提交失败,队列已满\\n", taskID) + } + } + + time.Sleep(1 * time.Second) // 等待任务完成 + bufferedPool.Stop() + + // 优先级工作池 + fmt.Printf(" 优先级工作池:\\n") + + priorityPool := NewPriorityWorkerPool(2) + priorityPool.Start() + + // 提交不同优先级的任务 + tasks := []PriorityTask{ + {Priority: 1, Name: "低优先级任务1"}, + {Priority: 3, Name: "高优先级任务1"}, + {Priority: 2, Name: "中优先级任务1"}, + {Priority: 3, Name: "高优先级任务2"}, + {Priority: 1, Name: "低优先级任务2"}, + } + + for _, task := range tasks { + priorityPool.Submit(task) + } + + time.Sleep(500 * time.Millisecond) + priorityPool.Stop() + + fmt.Println() +} + +// demonstrateDynamicWorkerPool 演示动态工作池 +func demonstrateDynamicWorkerPool() { + fmt.Println("3. 动态工作池:") + + // 动态工作池的特点 + fmt.Printf(" 动态工作池的特点:\\n") + fmt.Printf(" - 根据负载动态调整工作者数量\\n") + fmt.Printf(" - 自动扩容和缩容\\n") + fmt.Printf(" - 更好的资源利用率\\n") + fmt.Printf(" - 适应不同的工作负载\\n") + + // 动态工作池示例 + fmt.Printf(" 动态工作池示例:\\n") + + dynamicPool := NewDynamicWorkerPool(2, 8) // 最小2个,最大8个工作者 + dynamicPool.Start() + + // 模拟不同的负载模式 + fmt.Printf(" 阶段1: 轻负载\\n") + for i := 1; i <= 3; i++ { + taskID := i + dynamicPool.Submit(func() { + fmt.Printf(" 轻负载任务 %d\\n", taskID) + time.Sleep(200 * time.Millisecond) + }) + } + + time.Sleep(300 * time.Millisecond) + fmt.Printf(" 当前工作者数量: %d\\n", dynamicPool.WorkerCount()) + + fmt.Printf(" 阶段2: 重负载\\n") + for i := 1; i <= 12; i++ { + taskID := i + dynamicPool.Submit(func() { + fmt.Printf(" 重负载任务 %d\\n", taskID) + time.Sleep(100 * time.Millisecond) + }) + } + + time.Sleep(200 * time.Millisecond) + fmt.Printf(" 当前工作者数量: %d\\n", dynamicPool.WorkerCount()) + + fmt.Printf(" 阶段3: 负载降低\\n") + time.Sleep(1 * time.Second) + fmt.Printf(" 当前工作者数量: %d\\n", dynamicPool.WorkerCount()) + + dynamicPool.Stop() + + // 自适应工作池 + fmt.Printf(" 自适应工作池:\\n") + + adaptivePool := NewAdaptiveWorkerPool() + adaptivePool.Start() + + // 提交任务并观察自适应行为 + for i := 1; i <= 20; i++ { + taskID := i + adaptivePool.Submit(func() { + // 模拟不同执行时间的任务 + duration := time.Duration(rand.Intn(300)) * time.Millisecond + time.Sleep(duration) + fmt.Printf(" 自适应任务 %d 完成 (耗时: %v)\\n", taskID, duration) + }) + + if i%5 == 0 { + fmt.Printf(" 提交 %d 个任务后,工作者数量: %d\\n", i, adaptivePool.WorkerCount()) + } + } + + time.Sleep(2 * time.Second) + adaptivePool.Stop() + + fmt.Println() +} + +// demonstrateContextWorkerPool 演示带上下文的工作池 +func demonstrateContextWorkerPool() { + fmt.Println("4. 带上下文的工作池:") + + // 上下文工作池的优势 + fmt.Printf(" 上下文工作池的优势:\\n") + fmt.Printf(" - 支持取消和超时控制\\n") + fmt.Printf(" - 优雅的关闭机制\\n") + fmt.Printf(" - 更好的错误处理\\n") + fmt.Printf(" - 支持请求追踪\\n") + + // 带取消的工作池 + fmt.Printf(" 带取消的工作池:\\n") + + ctx, cancel := context.WithCancel(context.Background()) + contextPool := NewContextWorkerPool(3) + contextPool.Start(ctx) + + // 提交任务 + for i := 1; i <= 10; i++ { + taskID := i + contextPool.Submit(ContextTask{ + ID: taskID, + Fn: func(ctx context.Context) error { + select { + case <-ctx.Done(): + fmt.Printf(" 任务 %d 被取消\\n", taskID) + return ctx.Err() + case <-time.After(200 * time.Millisecond): + fmt.Printf(" 任务 %d 完成\\n", taskID) + return nil + } + }, + }) + } + + // 3秒后取消所有任务 + time.Sleep(300 * time.Millisecond) + fmt.Printf(" 取消所有任务\\n") + cancel() + + time.Sleep(100 * time.Millisecond) + + // 带超时的工作池 + fmt.Printf(" 带超时的工作池:\\n") + + timeoutCtx, timeoutCancel := context.WithTimeout(context.Background(), 500*time.Millisecond) + defer timeoutCancel() + + timeoutPool := NewContextWorkerPool(2) + timeoutPool.Start(timeoutCtx) + + // 提交一些长时间运行的任务 + for i := 1; i <= 5; i++ { + taskID := i + timeoutPool.Submit(ContextTask{ + ID: taskID, + Fn: func(ctx context.Context) error { + select { + case <-ctx.Done(): + fmt.Printf(" 超时任务 %d 被取消: %v\\n", taskID, ctx.Err()) + return ctx.Err() + case <-time.After(300 * time.Millisecond): + fmt.Printf(" 超时任务 %d 完成\\n", taskID) + return nil + } + }, + }) + } + + time.Sleep(600 * time.Millisecond) + + fmt.Println() +} + +// demonstrateErrorHandling 演示工作池的错误处理 +func demonstrateErrorHandling() { + fmt.Println("5. 工作池的错误处理:") + + // 错误处理的重要性 + fmt.Printf(" 错误处理的重要性:\\n") + fmt.Printf(" - 防止单个任务错误影响整个系统\\n") + fmt.Printf(" - 提供错误恢复机制\\n") + fmt.Printf(" - 记录和监控错误\\n") + fmt.Printf(" - 支持重试机制\\n") + + // 带错误处理的工作池 + fmt.Printf(" 带错误处理的工作池:\\n") + + errorPool := NewErrorHandlingWorkerPool(3) + errorPool.Start() + + // 提交一些可能失败的任务 + tasks := []ErrorTask{ + {ID: 1, ShouldFail: false, Data: "正常任务1"}, + {ID: 2, ShouldFail: true, Data: "错误任务1"}, + {ID: 3, ShouldFail: false, Data: "正常任务2"}, + {ID: 4, ShouldFail: true, Data: "错误任务2"}, + {ID: 5, ShouldFail: false, Data: "正常任务3"}, + } + + for _, task := range tasks { + errorPool.Submit(task) + } + + time.Sleep(500 * time.Millisecond) + + // 获取错误统计 + stats := errorPool.GetStats() + fmt.Printf(" 处理统计: 成功=%d, 失败=%d, 重试=%d\\n", + stats.Success, stats.Failed, stats.Retried) + + errorPool.Stop() + + // 带重试机制的工作池 + fmt.Printf(" 带重试机制的工作池:\\n") + + retryPool := NewRetryWorkerPool(2, 3) // 2个工作者,最多重试3次 + retryPool.Start() + + // 提交需要重试的任务 + retryTasks := []RetryTask{ + {ID: 1, MaxRetries: 2, Data: "重试任务1"}, + {ID: 2, MaxRetries: 1, Data: "重试任务2"}, + {ID: 3, MaxRetries: 3, Data: "重试任务3"}, + } + + for _, task := range retryTasks { + retryPool.Submit(task) + } + + time.Sleep(1 * time.Second) + retryPool.Stop() + + fmt.Println() +} + +// demonstrateWorkerPoolMonitoring 演示工作池的监控 +func demonstrateWorkerPoolMonitoring() { + fmt.Println("6. 工作池的监控:") + + // 监控的重要性 + fmt.Printf(" 监控的重要性:\\n") + fmt.Printf(" - 实时了解工作池状态\\n") + fmt.Printf(" - 性能调优的依据\\n") + fmt.Printf(" - 及时发现问题\\n") + fmt.Printf(" - 容量规划参考\\n") + + // 带监控的工作池 + fmt.Printf(" 带监控的工作池:\\n") + + monitoredPool := NewMonitoredWorkerPool(4) + monitoredPool.Start() + + // 启动监控 + go func() { + ticker := time.NewTicker(200 * time.Millisecond) + defer ticker.Stop() + + for i := 0; i < 5; i++ { + <-ticker.C + metrics := monitoredPool.GetMetrics() + fmt.Printf(" 监控: 活跃=%d, 队列=%d, 完成=%d, 平均耗时=%.2fms\\n", + metrics.ActiveWorkers, metrics.QueueSize, + metrics.CompletedTasks, metrics.AvgProcessTime) + } + }() + + // 提交任务 + for i := 1; i <= 20; i++ { + taskID := i + monitoredPool.Submit(MonitoredTask{ + ID: taskID, + Fn: func() { + // 模拟不同执行时间 + duration := time.Duration(rand.Intn(300)) * time.Millisecond + time.Sleep(duration) + }, + }) + } + + time.Sleep(1200 * time.Millisecond) + + // 最终统计 + finalMetrics := monitoredPool.GetMetrics() + fmt.Printf(" 最终统计: 总任务=%d, 完成=%d, 平均耗时=%.2fms\\n", + finalMetrics.TotalTasks, finalMetrics.CompletedTasks, + finalMetrics.AvgProcessTime) + + monitoredPool.Stop() + + fmt.Println() +} + +// demonstratePracticalApplications 演示实际应用场景 +func demonstratePracticalApplications() { + fmt.Println("7. 实际应用场景:") + + // Web 服务器请求处理 + fmt.Printf(" Web 服务器请求处理:\\n") + + webPool := NewWebServerPool(runtime.NumCPU()) + webPool.Start() + + // 模拟HTTP请求 + requests := []HTTPRequest{ + {ID: 1, Method: "GET", URL: "/api/users", Body: ""}, + {ID: 2, Method: "POST", URL: "/api/users", Body: `{"name":"Alice"}`}, + {ID: 3, Method: "GET", URL: "/api/orders", Body: ""}, + {ID: 4, Method: "PUT", URL: "/api/users/1", Body: `{"name":"Bob"}`}, + {ID: 5, Method: "DELETE", URL: "/api/users/2", Body: ""}, + } + + for _, req := range requests { + webPool.HandleRequest(req) + } + + time.Sleep(300 * time.Millisecond) + webPool.Stop() + + // 图片处理服务 + fmt.Printf(" 图片处理服务:\\n") + + imagePool := NewImageProcessingPool(3) + imagePool.Start() + + // 模拟图片处理任务 + images := []ImageTask{ + {ID: 1, Filename: "photo1.jpg", Operations: []string{"resize", "compress"}}, + {ID: 2, Filename: "photo2.png", Operations: []string{"crop", "filter"}}, + {ID: 3, Filename: "photo3.gif", Operations: []string{"resize", "watermark"}}, + {ID: 4, Filename: "photo4.jpg", Operations: []string{"rotate", "compress"}}, + } + + for _, img := range images { + imagePool.ProcessImage(img) + } + + time.Sleep(500 * time.Millisecond) + imagePool.Stop() + + // 数据处理管道 + fmt.Printf(" 数据处理管道:\\n") + + pipeline := NewDataPipeline(2, 2, 2) // 读取、处理、写入各2个工作者 + pipeline.Start() + + // 模拟数据处理 + dataItems := []DataItem{ + {ID: 1, Content: "数据1", Type: "json"}, + {ID: 2, Content: "数据2", Type: "xml"}, + {ID: 3, Content: "数据3", Type: "csv"}, + {ID: 4, Content: "数据4", Type: "json"}, + {ID: 5, Content: "数据5", Type: "xml"}, + } + + for _, item := range dataItems { + pipeline.ProcessData(item) + } + + time.Sleep(800 * time.Millisecond) + pipeline.Stop() + + // 批量任务处理 + fmt.Printf(" 批量任务处理:\\n") + + batchPool := NewBatchWorkerPool(3, 5) // 3个工作者,批量大小5 + batchPool.Start() + + // 提交大量小任务 + for i := 1; i <= 23; i++ { + batchPool.Submit(BatchItem{ + ID: i, + Data: fmt.Sprintf("批量数据-%d", i), + }) + } + + time.Sleep(600 * time.Millisecond) + batchPool.Stop() + + fmt.Println() +} + +// ========== 类型定义和辅助函数 ========== + +// Job 基本任务 +type Job struct { + ID int + Data string +} + +// Result 任务结果 +type Result struct { + JobID int + Message string +} + +// worker 基本工作者函数 +func worker(id int, jobs <-chan Job, results chan<- Result) { + for job := range jobs { + fmt.Printf(" 工作者 %d 开始处理任务 %d\\n", id, job.ID) + time.Sleep(100 * time.Millisecond) // 模拟工作 + results <- Result{ + JobID: job.ID, + Message: fmt.Sprintf("工作者 %d 完成任务 %d: %s", id, job.ID, job.Data), + } + } +} + +// SimpleWorkerPool 简单工作池 +type SimpleWorkerPool struct { + workerCount int + taskQueue chan func() + quit chan bool + wg sync.WaitGroup +} + +func NewSimpleWorkerPool(workerCount int) *SimpleWorkerPool { + return &SimpleWorkerPool{ + workerCount: workerCount, + taskQueue: make(chan func()), + quit: make(chan bool), + } +} + +func (p *SimpleWorkerPool) Start() { + for i := 0; i < p.workerCount; i++ { + p.wg.Add(1) + go p.worker(i + 1) + } +} + +func (p *SimpleWorkerPool) Submit(task func()) { + p.taskQueue <- task +} + +func (p *SimpleWorkerPool) Stop() { + close(p.taskQueue) + p.wg.Wait() +} + +func (p *SimpleWorkerPool) worker(id int) { + defer p.wg.Done() + for task := range p.taskQueue { + task() + } +} + +// BufferedWorkerPool 缓冲工作池 +type BufferedWorkerPool struct { + workerCount int + taskQueue chan func() + quit chan bool + wg sync.WaitGroup +} + +func NewBufferedWorkerPool(workerCount, bufferSize int) *BufferedWorkerPool { + return &BufferedWorkerPool{ + workerCount: workerCount, + taskQueue: make(chan func(), bufferSize), + quit: make(chan bool), + } +} + +func (p *BufferedWorkerPool) Start() { + for i := 0; i < p.workerCount; i++ { + p.wg.Add(1) + go p.worker(i + 1) + } +} + +func (p *BufferedWorkerPool) TrySubmit(task func()) bool { + select { + case p.taskQueue <- task: + return true + default: + return false + } +} + +func (p *BufferedWorkerPool) Stop() { + close(p.taskQueue) + p.wg.Wait() +} + +func (p *BufferedWorkerPool) worker(id int) { + defer p.wg.Done() + for task := range p.taskQueue { + task() + } +} + +// PriorityTask 优先级任务 +type PriorityTask struct { + Priority int + Name string +} + +// PriorityWorkerPool 优先级工作池 +type PriorityWorkerPool struct { + workerCount int + taskQueue chan PriorityTask + wg sync.WaitGroup +} + +func NewPriorityWorkerPool(workerCount int) *PriorityWorkerPool { + return &PriorityWorkerPool{ + workerCount: workerCount, + taskQueue: make(chan PriorityTask, 100), + } +} + +func (p *PriorityWorkerPool) Start() { + for i := 0; i < p.workerCount; i++ { + p.wg.Add(1) + go p.worker(i + 1) + } +} + +func (p *PriorityWorkerPool) Submit(task PriorityTask) { + p.taskQueue <- task +} + +func (p *PriorityWorkerPool) Stop() { + close(p.taskQueue) + p.wg.Wait() +} + +func (p *PriorityWorkerPool) worker(id int) { + defer p.wg.Done() + for task := range p.taskQueue { + fmt.Printf(" 工作者 %d 执行 %s (优先级: %d)\\n", + id, task.Name, task.Priority) + time.Sleep(100 * time.Millisecond) + } +} + +// DynamicWorkerPool 动态工作池 +type DynamicWorkerPool struct { + minWorkers int + maxWorkers int + currentWorkers int + taskQueue chan func() + workerQueue chan chan func() + quit chan bool + wg sync.WaitGroup + mu sync.RWMutex +} + +func NewDynamicWorkerPool(minWorkers, maxWorkers int) *DynamicWorkerPool { + return &DynamicWorkerPool{ + minWorkers: minWorkers, + maxWorkers: maxWorkers, + taskQueue: make(chan func()), + workerQueue: make(chan chan func(), maxWorkers), + quit: make(chan bool), + } +} + +func (p *DynamicWorkerPool) Start() { + // 启动最小数量的工作者 + for i := 0; i < p.minWorkers; i++ { + p.addWorker() + } + + // 启动调度器 + go p.dispatcher() +} + +func (p *DynamicWorkerPool) Submit(task func()) { + p.taskQueue <- task +} + +func (p *DynamicWorkerPool) WorkerCount() int { + p.mu.RLock() + defer p.mu.RUnlock() + return p.currentWorkers +} + +func (p *DynamicWorkerPool) Stop() { + close(p.quit) + p.wg.Wait() +} + +func (p *DynamicWorkerPool) addWorker() { + p.mu.Lock() + defer p.mu.Unlock() + + if p.currentWorkers < p.maxWorkers { + p.currentWorkers++ + p.wg.Add(1) + go p.worker(p.currentWorkers) + } +} + +func (p *DynamicWorkerPool) worker(id int) { + defer p.wg.Done() + defer func() { + p.mu.Lock() + p.currentWorkers-- + p.mu.Unlock() + }() + + taskChan := make(chan func()) + + for { + // 注册工作者 + p.workerQueue <- taskChan + + select { + case task := <-taskChan: + task() + case <-p.quit: + return + } + } +} + +func (p *DynamicWorkerPool) dispatcher() { + for { + select { + case task := <-p.taskQueue: + select { + case workerTaskChan := <-p.workerQueue: + workerTaskChan <- task + default: + // 没有可用工作者,尝试添加新工作者 + p.addWorker() + workerTaskChan := <-p.workerQueue + workerTaskChan <- task + } + case <-p.quit: + return + } + } +} + +// AdaptiveWorkerPool 自适应工作池 +type AdaptiveWorkerPool struct { + workers map[int]*AdaptiveWorker + taskQueue chan func() + workerQueue chan chan func() + quit chan bool + wg sync.WaitGroup + mu sync.RWMutex + nextID int +} + +type AdaptiveWorker struct { + id int + taskChan chan func() + quit chan bool + pool *AdaptiveWorkerPool +} + +func NewAdaptiveWorkerPool() *AdaptiveWorkerPool { + return &AdaptiveWorkerPool{ + workers: make(map[int]*AdaptiveWorker), + taskQueue: make(chan func()), + workerQueue: make(chan chan func(), 100), + quit: make(chan bool), + } +} + +func (p *AdaptiveWorkerPool) Start() { + // 启动初始工作者 + p.addWorker() + go p.dispatcher() + go p.monitor() +} + +func (p *AdaptiveWorkerPool) Submit(task func()) { + p.taskQueue <- task +} + +func (p *AdaptiveWorkerPool) WorkerCount() int { + p.mu.RLock() + defer p.mu.RUnlock() + return len(p.workers) +} + +func (p *AdaptiveWorkerPool) Stop() { + close(p.quit) + p.wg.Wait() +} + +func (p *AdaptiveWorkerPool) addWorker() { + p.mu.Lock() + defer p.mu.Unlock() + + p.nextID++ + worker := &AdaptiveWorker{ + id: p.nextID, + taskChan: make(chan func()), + quit: make(chan bool), + pool: p, + } + + p.workers[worker.id] = worker + p.wg.Add(1) + go worker.run() +} + +func (p *AdaptiveWorkerPool) removeWorker(id int) { + p.mu.Lock() + defer p.mu.Unlock() + + if worker, exists := p.workers[id]; exists { + close(worker.quit) + delete(p.workers, id) + } +} + +func (p *AdaptiveWorkerPool) dispatcher() { + for { + select { + case task := <-p.taskQueue: + select { + case workerTaskChan := <-p.workerQueue: + workerTaskChan <- task + default: + // 需要更多工作者 + p.addWorker() + workerTaskChan := <-p.workerQueue + workerTaskChan <- task + } + case <-p.quit: + return + } + } +} + +func (p *AdaptiveWorkerPool) monitor() { + ticker := time.NewTicker(1 * time.Second) + defer ticker.Stop() + + for { + select { + case <-ticker.C: + // 简单的自适应逻辑:如果队列为空且工作者多于1个,减少工作者 + if len(p.taskQueue) == 0 && len(p.workers) > 1 { + p.mu.RLock() + var workerID int + for id := range p.workers { + workerID = id + break + } + p.mu.RUnlock() + p.removeWorker(workerID) + } + case <-p.quit: + return + } + } +} + +func (w *AdaptiveWorker) run() { + defer w.pool.wg.Done() + + for { + // 注册到工作者队列 + w.pool.workerQueue <- w.taskChan + + select { + case task := <-w.taskChan: + task() + case <-w.quit: + return + case <-w.pool.quit: + return + } + } +} + +// ContextTask 上下文任务 +type ContextTask struct { + ID int + Fn func(context.Context) error +} + +// ContextWorkerPool 上下文工作池 +type ContextWorkerPool struct { + workerCount int + taskQueue chan ContextTask + wg sync.WaitGroup +} + +func NewContextWorkerPool(workerCount int) *ContextWorkerPool { + return &ContextWorkerPool{ + workerCount: workerCount, + taskQueue: make(chan ContextTask), + } +} + +func (p *ContextWorkerPool) Start(ctx context.Context) { + for i := 0; i < p.workerCount; i++ { + p.wg.Add(1) + go p.worker(ctx, i+1) + } +} + +func (p *ContextWorkerPool) Submit(task ContextTask) { + p.taskQueue <- task +} + +func (p *ContextWorkerPool) worker(ctx context.Context, id int) { + defer p.wg.Done() + + for { + select { + case task := <-p.taskQueue: + task.Fn(ctx) + case <-ctx.Done(): + return + } + } +} + +// ErrorTask 错误任务 +type ErrorTask struct { + ID int + ShouldFail bool + Data string +} + +// ErrorStats 错误统计 +type ErrorStats struct { + Success int + Failed int + Retried int +} + +// ErrorHandlingWorkerPool 错误处理工作池 +type ErrorHandlingWorkerPool struct { + workerCount int + taskQueue chan ErrorTask + wg sync.WaitGroup + stats ErrorStats + statsMu sync.Mutex +} + +func NewErrorHandlingWorkerPool(workerCount int) *ErrorHandlingWorkerPool { + return &ErrorHandlingWorkerPool{ + workerCount: workerCount, + taskQueue: make(chan ErrorTask), + } +} + +func (p *ErrorHandlingWorkerPool) Start() { + for i := 0; i < p.workerCount; i++ { + p.wg.Add(1) + go p.worker(i + 1) + } +} + +func (p *ErrorHandlingWorkerPool) Submit(task ErrorTask) { + p.taskQueue <- task +} + +func (p *ErrorHandlingWorkerPool) GetStats() ErrorStats { + p.statsMu.Lock() + defer p.statsMu.Unlock() + return p.stats +} + +func (p *ErrorHandlingWorkerPool) Stop() { + close(p.taskQueue) + p.wg.Wait() +} + +func (p *ErrorHandlingWorkerPool) worker(id int) { + defer p.wg.Done() + + for task := range p.taskQueue { + err := p.processTask(task) + + p.statsMu.Lock() + if err != nil { + p.stats.Failed++ + fmt.Printf(" 工作者 %d 任务 %d 失败: %v\\n", id, task.ID, err) + } else { + p.stats.Success++ + fmt.Printf(" 工作者 %d 任务 %d 成功\\n", id, task.ID) + } + p.statsMu.Unlock() + } +} + +func (p *ErrorHandlingWorkerPool) processTask(task ErrorTask) error { + time.Sleep(50 * time.Millisecond) + + if task.ShouldFail { + return fmt.Errorf("任务 %d 模拟失败", task.ID) + } + + return nil +} + +// RetryTask 重试任务 +type RetryTask struct { + ID int + MaxRetries int + Data string + attempts int +} + +// RetryWorkerPool 重试工作池 +type RetryWorkerPool struct { + workerCount int + maxRetries int + taskQueue chan RetryTask + retryQueue chan RetryTask + wg sync.WaitGroup +} + +func NewRetryWorkerPool(workerCount, maxRetries int) *RetryWorkerPool { + return &RetryWorkerPool{ + workerCount: workerCount, + maxRetries: maxRetries, + taskQueue: make(chan RetryTask), + retryQueue: make(chan RetryTask, 100), + } +} + +func (p *RetryWorkerPool) Start() { + for i := 0; i < p.workerCount; i++ { + p.wg.Add(1) + go p.worker(i + 1) + } + + // 启动重试处理器 + p.wg.Add(1) + go p.retryHandler() +} + +func (p *RetryWorkerPool) Submit(task RetryTask) { + p.taskQueue <- task +} + +func (p *RetryWorkerPool) Stop() { + close(p.taskQueue) + close(p.retryQueue) + p.wg.Wait() +} + +func (p *RetryWorkerPool) worker(id int) { + defer p.wg.Done() + + for task := range p.taskQueue { + task.attempts++ + + // 模拟任务执行(30%成功率) + success := rand.Float32() < 0.3 + + if success { + fmt.Printf(" 工作者 %d 任务 %d 成功 (尝试 %d 次)\\n", + id, task.ID, task.attempts) + } else if task.attempts < task.MaxRetries { + fmt.Printf(" 工作者 %d 任务 %d 失败,准备重试 (尝试 %d/%d)\\n", + id, task.ID, task.attempts, task.MaxRetries) + p.retryQueue <- task + } else { + fmt.Printf(" 工作者 %d 任务 %d 最终失败 (尝试 %d 次)\\n", + id, task.ID, task.attempts) + } + } +} + +func (p *RetryWorkerPool) retryHandler() { + defer p.wg.Done() + + for task := range p.retryQueue { + // 延迟重试 + time.Sleep(100 * time.Millisecond) + p.taskQueue <- task + } +} + +// MonitoredTask 监控任务 +type MonitoredTask struct { + ID int + Fn func() +} + +// WorkerPoolMetrics 工作池指标 +type WorkerPoolMetrics struct { + ActiveWorkers int + QueueSize int + TotalTasks int + CompletedTasks int + AvgProcessTime float64 +} + +// MonitoredWorkerPool 监控工作池 +type MonitoredWorkerPool struct { + workerCount int + taskQueue chan MonitoredTask + wg sync.WaitGroup + metrics WorkerPoolMetrics + metricsMu sync.RWMutex + processTimes []time.Duration + activeWorkers int +} + +func NewMonitoredWorkerPool(workerCount int) *MonitoredWorkerPool { + return &MonitoredWorkerPool{ + workerCount: workerCount, + taskQueue: make(chan MonitoredTask, 100), + processTimes: make([]time.Duration, 0), + } +} + +func (p *MonitoredWorkerPool) Start() { + for i := 0; i < p.workerCount; i++ { + p.wg.Add(1) + go p.worker(i + 1) + } +} + +func (p *MonitoredWorkerPool) Submit(task MonitoredTask) { + p.metricsMu.Lock() + p.metrics.TotalTasks++ + p.metricsMu.Unlock() + + p.taskQueue <- task +} + +func (p *MonitoredWorkerPool) GetMetrics() WorkerPoolMetrics { + p.metricsMu.RLock() + defer p.metricsMu.RUnlock() + + metrics := p.metrics + metrics.QueueSize = len(p.taskQueue) + metrics.ActiveWorkers = p.activeWorkers + + // 计算平均处理时间 + if len(p.processTimes) > 0 { + var total time.Duration + for _, t := range p.processTimes { + total += t + } + metrics.AvgProcessTime = float64(total.Nanoseconds()) / float64(len(p.processTimes)) / 1e6 + } + + return metrics +} + +func (p *MonitoredWorkerPool) Stop() { + close(p.taskQueue) + p.wg.Wait() +} + +func (p *MonitoredWorkerPool) worker(id int) { + defer p.wg.Done() + + for task := range p.taskQueue { + p.metricsMu.Lock() + p.activeWorkers++ + p.metricsMu.Unlock() + + start := time.Now() + task.Fn() + duration := time.Since(start) + + p.metricsMu.Lock() + p.activeWorkers-- + p.metrics.CompletedTasks++ + p.processTimes = append(p.processTimes, duration) + + // 保持最近100个处理时间 + if len(p.processTimes) > 100 { + p.processTimes = p.processTimes[1:] + } + p.metricsMu.Unlock() + } +} + +// HTTPRequest HTTP请求 +type HTTPRequest struct { + ID int + Method string + URL string + Body string +} + +// WebServerPool Web服务器池 +type WebServerPool struct { + workerCount int + requestChan chan HTTPRequest + wg sync.WaitGroup +} + +func NewWebServerPool(workerCount int) *WebServerPool { + return &WebServerPool{ + workerCount: workerCount, + requestChan: make(chan HTTPRequest, 100), + } +} + +func (p *WebServerPool) Start() { + for i := 0; i < p.workerCount; i++ { + p.wg.Add(1) + go p.worker(i + 1) + } +} + +func (p *WebServerPool) HandleRequest(req HTTPRequest) { + p.requestChan <- req +} + +func (p *WebServerPool) Stop() { + close(p.requestChan) + p.wg.Wait() +} + +func (p *WebServerPool) worker(id int) { + defer p.wg.Done() + + for req := range p.requestChan { + // 模拟请求处理 + processingTime := time.Duration(rand.Intn(100)) * time.Millisecond + time.Sleep(processingTime) + + fmt.Printf(" 工作者 %d 处理请求 %d: %s %s (耗时: %v)\\n", + id, req.ID, req.Method, req.URL, processingTime) + } +} + +// ImageTask 图片任务 +type ImageTask struct { + ID int + Filename string + Operations []string +} + +// ImageProcessingPool 图片处理池 +type ImageProcessingPool struct { + workerCount int + taskChan chan ImageTask + wg sync.WaitGroup +} + +func NewImageProcessingPool(workerCount int) *ImageProcessingPool { + return &ImageProcessingPool{ + workerCount: workerCount, + taskChan: make(chan ImageTask, 50), + } +} + +func (p *ImageProcessingPool) Start() { + for i := 0; i < p.workerCount; i++ { + p.wg.Add(1) + go p.worker(i + 1) + } +} + +func (p *ImageProcessingPool) ProcessImage(task ImageTask) { + p.taskChan <- task +} + +func (p *ImageProcessingPool) Stop() { + close(p.taskChan) + p.wg.Wait() +} + +func (p *ImageProcessingPool) worker(id int) { + defer p.wg.Done() + + for task := range p.taskChan { + fmt.Printf(" 工作者 %d 处理图片 %s:\\n", id, task.Filename) + + for _, op := range task.Operations { + // 模拟图片操作 + time.Sleep(50 * time.Millisecond) + fmt.Printf(" - 执行操作: %s\\n", op) + } + + fmt.Printf(" 图片 %s 处理完成\\n", task.Filename) + } +} + +// DataItem 数据项 +type DataItem struct { + ID int + Content string + Type string +} + +// DataPipeline 数据处理管道 +type DataPipeline struct { + readWorkers int + processWorkers int + writeWorkers int + + inputChan chan DataItem + processedChan chan DataItem + outputChan chan DataItem + + wg sync.WaitGroup +} + +func NewDataPipeline(readWorkers, processWorkers, writeWorkers int) *DataPipeline { + return &DataPipeline{ + readWorkers: readWorkers, + processWorkers: processWorkers, + writeWorkers: writeWorkers, + inputChan: make(chan DataItem, 20), + processedChan: make(chan DataItem, 20), + outputChan: make(chan DataItem, 20), + } +} + +func (p *DataPipeline) Start() { + // 启动读取工作者 + for i := 0; i < p.readWorkers; i++ { + p.wg.Add(1) + go p.readWorker(i + 1) + } + + // 启动处理工作者 + for i := 0; i < p.processWorkers; i++ { + p.wg.Add(1) + go p.processWorker(i + 1) + } + + // 启动写入工作者 + for i := 0; i < p.writeWorkers; i++ { + p.wg.Add(1) + go p.writeWorker(i + 1) + } +} + +func (p *DataPipeline) ProcessData(item DataItem) { + p.inputChan <- item +} + +func (p *DataPipeline) Stop() { + close(p.inputChan) + p.wg.Wait() +} + +func (p *DataPipeline) readWorker(id int) { + defer p.wg.Done() + + for item := range p.inputChan { + // 模拟读取处理 + time.Sleep(30 * time.Millisecond) + fmt.Printf(" 读取工作者 %d 读取数据 %d\\n", id, item.ID) + p.processedChan <- item + } + + if id == 1 { // 只让第一个工作者关闭下一阶段 + close(p.processedChan) + } +} + +func (p *DataPipeline) processWorker(id int) { + defer p.wg.Done() + + for item := range p.processedChan { + // 模拟数据处理 + time.Sleep(50 * time.Millisecond) + item.Content = fmt.Sprintf("处理后的%s", item.Content) + fmt.Printf(" 处理工作者 %d 处理数据 %d\\n", id, item.ID) + p.outputChan <- item + } + + if id == 1 { // 只让第一个工作者关闭下一阶段 + close(p.outputChan) + } +} + +func (p *DataPipeline) writeWorker(id int) { + defer p.wg.Done() + + for item := range p.outputChan { + // 模拟写入处理 + time.Sleep(20 * time.Millisecond) + fmt.Printf(" 写入工作者 %d 写入数据 %d: %s\\n", id, item.ID, item.Content) + } +} + +// BatchItem 批量项 +type BatchItem struct { + ID int + Data string +} + +// BatchWorkerPool 批量工作池 +type BatchWorkerPool struct { + workerCount int + batchSize int + itemChan chan BatchItem + wg sync.WaitGroup +} + +func NewBatchWorkerPool(workerCount, batchSize int) *BatchWorkerPool { + return &BatchWorkerPool{ + workerCount: workerCount, + batchSize: batchSize, + itemChan: make(chan BatchItem, 100), + } +} + +func (p *BatchWorkerPool) Start() { + for i := 0; i < p.workerCount; i++ { + p.wg.Add(1) + go p.worker(i + 1) + } +} + +func (p *BatchWorkerPool) Submit(item BatchItem) { + p.itemChan <- item +} + +func (p *BatchWorkerPool) Stop() { + close(p.itemChan) + p.wg.Wait() +} + +func (p *BatchWorkerPool) worker(id int) { + defer p.wg.Done() + + batch := make([]BatchItem, 0, p.batchSize) + + for item := range p.itemChan { + batch = append(batch, item) + + if len(batch) >= p.batchSize { + p.processBatch(id, batch) + batch = batch[:0] // 重置批次 + } + } + + // 处理剩余的项目 + if len(batch) > 0 { + p.processBatch(id, batch) + } +} + +func (p *BatchWorkerPool) processBatch(workerID int, batch []BatchItem) { + fmt.Printf(" 工作者 %d 处理批次 (大小: %d):\\n", workerID, len(batch)) + + for _, item := range batch { + fmt.Printf(" - 处理项目 %d: %s\\n", item.ID, item.Data) + } + + // 模拟批量处理时间 + time.Sleep(100 * time.Millisecond) + fmt.Printf(" 工作者 %d 批次处理完成\\n", workerID) +} + +/* +运行这个程序: +go run 05-worker-pools.go + +学习要点: +1. 工作池模式是控制并发的重要技术 +2. 可以根据需求实现不同类型的工作池 +3. 工作池提供了更好的资源控制和系统稳定性 +4. 支持动态调整、错误处理、监控等高级特性 +5. 在实际应用中有广泛的使用场景 + +工作池的优势: +1. 控制并发数量,避免资源耗尽 +2. 重用 goroutine,减少创建销毁开销 +3. 提供任务队列,平滑处理突发负载 +4. 支持优雅关闭和错误处理 +5. 便于监控和调优 + +工作池类型: +1. 固定大小工作池:预先创建固定数量的工作者 +2. 缓冲工作池:带有任务队列缓冲 +3. 动态工作池:根据负载动态调整工作者数量 +4. 优先级工作池:支持任务优先级 +5. 上下文工作池:支持取消和超时 + +高级特性: +1. 错误处理:捕获和处理任务错误 +2. 重试机制:自动重试失败的任务 +3. 监控指标:实时监控工作池状态 +4. 优雅关闭:安全地停止工作池 +5. 负载均衡:合理分配任务 + +实际应用: +1. Web 服务器:处理 HTTP 请求 +2. 图片处理:批量处理图片 +3. 数据处理:ETL 数据管道 +4. 批量任务:批量处理业务逻辑 +5. 消息队列:处理消息 + +设计考虑: +1. 工作者数量:根据 CPU 核心数和任务类型 +2. 队列大小:平衡内存使用和响应时间 +3. 任务粒度:避免任务过大或过小 +4. 错误策略:决定如何处理失败任务 +5. 监控指标:选择合适的监控维度 + +性能优化: +1. 合理设置工作者数量 +2. 使用缓冲队列减少阻塞 +3. 批量处理提高效率 +4. 避免频繁创建销毁 +5. 监控和调优关键指标 + +最佳实践: +1. 根据任务特性选择合适的工作池类型 +2. 实现优雅关闭机制 +3. 添加监控和日志 +4. 处理 panic 和错误 +5. 进行性能测试和调优 +*/ diff --git a/golang-learning/07-error-handling/01-basic-errors.go b/golang-learning/07-error-handling/01-basic-errors.go new file mode 100644 index 0000000..aa67173 --- /dev/null +++ b/golang-learning/07-error-handling/01-basic-errors.go @@ -0,0 +1,957 @@ +/* +01-basic-errors.go - Go 语言基础错误处理详解 + +学习目标: +1. 理解 Go 语言的错误处理哲学 +2. 掌握 error 接口的使用 +3. 学会基本的错误处理模式 +4. 了解错误传播和包装 +5. 掌握错误处理的最佳实践 + +知识点: +- error 接口的定义和实现 +- 错误的创建和返回 +- 错误检查和处理 +- 错误传播和包装 +- 错误处理的惯用法 +- 错误信息的设计 +*/ + +package main + +import ( + "crypto/rand" + "encoding/json" + "errors" + "fmt" + "os" + "strings" + "sync" + "time" +) + +func main() { + fmt.Println("=== Go 语言基础错误处理详解 ===\\n") + + // 演示错误接口的基本概念 + demonstrateErrorInterface() + + // 演示错误的创建方式 + demonstrateErrorCreation() + + // 演示错误检查和处理 + demonstrateErrorHandling() + + // 演示错误传播 + demonstrateErrorPropagation() + + // 演示错误包装 + demonstrateErrorWrapping() + + // 演示错误处理模式 + demonstrateErrorPatterns() + + // 演示实际应用场景 + demonstratePracticalExamples() +} + +// demonstrateErrorInterface 演示错误接口的基本概念 +func demonstrateErrorInterface() { + fmt.Println("1. 错误接口的基本概念:") + + // error 接口的定义 + fmt.Printf(" error 接口的定义:\\n") + fmt.Printf(" type error interface {\\n") + fmt.Printf(" Error() string\\n") + fmt.Printf(" }\\n") + fmt.Printf("\\n") + fmt.Printf(" 错误处理的特点:\\n") + fmt.Printf(" - 错误是值,可以像其他值一样传递\\n") + fmt.Printf(" - 使用多返回值模式处理错误\\n") + fmt.Printf(" - 显式错误检查,不隐藏错误\\n") + fmt.Printf(" - 错误应该被处理,不应该被忽略\\n") + fmt.Printf(" - 错误信息应该清晰、有用\\n") + + // 基本错误示例 + fmt.Printf(" 基本错误示例:\\n") + + // 成功的情况 + result, err := divide(10, 2) + if err != nil { + fmt.Printf(" 错误: %v\\n", err) + } else { + fmt.Printf(" 10 / 2 = %.2f\\n", result) + } + + // 错误的情况 + result, err = divide(10, 0) + if err != nil { + fmt.Printf(" 错误: %v\\n", err) + } else { + fmt.Printf(" 10 / 0 = %.2f\\n", result) + } + + // nil 错误检查 + fmt.Printf(" nil 错误检查:\\n") + + var nilError error + fmt.Printf(" nil 错误: %v\\n", nilError) + fmt.Printf(" nil 错误 == nil: %t\\n", nilError == nil) + + // 错误比较 + fmt.Printf(" 错误比较:\\n") + + err1 := errors.New("相同的错误") + err2 := errors.New("相同的错误") + fmt.Printf(" err1 == err2: %t (内容相同但不是同一个对象)\\n", err1 == err2) + fmt.Printf(" err1.Error() == err2.Error(): %t\\n", err1.Error() == err2.Error()) + + fmt.Println() +} + +// demonstrateErrorCreation 演示错误的创建方式 +func demonstrateErrorCreation() { + fmt.Println("2. 错误的创建方式:") + + // 使用 errors.New 创建错误 + fmt.Printf(" 使用 errors.New 创建错误:\\n") + + err1 := errors.New("这是一个简单的错误") + fmt.Printf(" 错误1: %v\\n", err1) + + // 使用 fmt.Errorf 创建格式化错误 + fmt.Printf(" 使用 fmt.Errorf 创建格式化错误:\\n") + + username := "alice" + err2 := fmt.Errorf("用户 %s 不存在", username) + fmt.Printf(" 错误2: %v\\n", err2) + + // 创建带有更多信息的错误 + age := -5 + err3 := fmt.Errorf("无效的年龄值: %d (年龄必须大于0)", age) + fmt.Printf(" 错误3: %v\\n", err3) + + // 使用预定义错误 + fmt.Printf(" 使用预定义错误:\\n") + + predefinedErrors := []error{ + ErrInvalidInput, + ErrNotFound, + ErrPermissionDenied, + ErrTimeout, + } + + for i, err := range predefinedErrors { + fmt.Printf(" 预定义错误%d: %v\\n", i+1, err) + } + + // 条件性错误创建 + fmt.Printf(" 条件性错误创建:\\n") + + testValues := []int{-1, 0, 5, 101} + for _, value := range testValues { + if err := validateAge(value); err != nil { + fmt.Printf(" 验证年龄 %d: %v\\n", value, err) + } else { + fmt.Printf(" 验证年龄 %d: 有效\\n", value) + } + } + + fmt.Println() +} + +// demonstrateErrorHandling 演示错误检查和处理 +func demonstrateErrorHandling() { + fmt.Println("3. 错误检查和处理:") + + // 基本错误检查模式 + fmt.Printf(" 基本错误检查模式:\\n") + + // 立即检查错误 + content, err := readFile("example.txt") + if err != nil { + fmt.Printf(" 读取文件失败: %v\\n", err) + } else { + fmt.Printf(" 文件内容: %s\\n", content) + } + + // 多个操作的错误处理 + fmt.Printf(" 多个操作的错误处理:\\n") + + err = performMultipleOperations() + if err != nil { + fmt.Printf(" 多个操作失败: %v\\n", err) + } else { + fmt.Printf(" 所有操作成功完成\\n") + } + + // 错误类型检查 + fmt.Printf(" 错误类型检查:\\n") + + testOperations := []func() error{ + func() error { return ErrNotFound }, + func() error { return ErrPermissionDenied }, + func() error { return fmt.Errorf("未知错误") }, + func() error { return nil }, + } + + for i, op := range testOperations { + err := op() + fmt.Printf(" 操作%d: ", i+1) + handleSpecificError(err) + } + + // 错误恢复 + fmt.Printf(" 错误恢复:\\n") + + data, err := fetchDataWithRetry("https://api.example.com/data", 3) + if err != nil { + fmt.Printf(" 获取数据失败: %v\\n", err) + } else { + fmt.Printf(" 获取数据成功: %s\\n", data) + } + + // 部分失败处理 + fmt.Printf(" 部分失败处理:\\n") + + results, errors := processBatch([]string{"item1", "item2", "invalid", "item4"}) + fmt.Printf(" 成功处理: %v\\n", results) + fmt.Printf(" 处理错误: %v\\n", errors) + + fmt.Println() +} + +// demonstrateErrorPropagation 演示错误传播 +func demonstrateErrorPropagation() { + fmt.Println("4. 错误传播:") + + // 简单错误传播 + fmt.Printf(" 简单错误传播:\\n") + + result, err := calculateTotal([]float64{10.5, 20.0, -5.0, 15.5}) + if err != nil { + fmt.Printf(" 计算总和失败: %v\\n", err) + } else { + fmt.Printf(" 总和: %.2f\\n", result) + } + + // 带上下文的错误传播 + fmt.Printf(" 带上下文的错误传播:\\n") + + user, err := getUserProfile("nonexistent_user") + if err != nil { + fmt.Printf(" 获取用户资料失败: %v\\n", err) + } else { + fmt.Printf(" 用户资料: %+v\\n", user) + } + + // 错误链 + fmt.Printf(" 错误链:\\n") + + err = processOrder("invalid_order_id") + if err != nil { + fmt.Printf(" 处理订单失败: %v\\n", err) + + // 展示错误链 + fmt.Printf(" 错误链分析:\\n") + printErrorChain(err, " ") + } + + // 选择性错误传播 + fmt.Printf(" 选择性错误传播:\\n") + + results := []string{} + errors := []error{} + + items := []string{"valid1", "invalid", "valid2", "error", "valid3"} + for _, item := range items { + result, err := processItem(item) + if err != nil { + errors = append(errors, fmt.Errorf("处理 %s 失败: %w", item, err)) + } else { + results = append(results, result) + } + } + + fmt.Printf(" 成功结果: %v\\n", results) + if len(errors) > 0 { + fmt.Printf(" 错误列表:\\n") + for _, err := range errors { + fmt.Printf(" - %v\\n", err) + } + } + + fmt.Println() +} + +// demonstrateErrorWrapping 演示错误包装 +func demonstrateErrorWrapping() { + fmt.Println("5. 错误包装:") + + // 基本错误包装 + fmt.Printf(" 基本错误包装:\\n") + + originalErr := errors.New("原始错误") + wrappedErr := fmt.Errorf("包装错误: %w", originalErr) + + fmt.Printf(" 原始错误: %v\\n", originalErr) + fmt.Printf(" 包装错误: %v\\n", wrappedErr) + + // 错误解包 + fmt.Printf(" 错误解包:\\n") + + unwrappedErr := errors.Unwrap(wrappedErr) + fmt.Printf(" 解包后的错误: %v\\n", unwrappedErr) + fmt.Printf(" 解包后是否为原始错误: %t\\n", unwrappedErr == originalErr) + + // 错误检查 (errors.Is) + fmt.Printf(" 错误检查 (errors.Is):\\n") + + fmt.Printf(" wrappedErr 是否为 originalErr: %t\\n", errors.Is(wrappedErr, originalErr)) + fmt.Printf(" wrappedErr 是否为 ErrNotFound: %t\\n", errors.Is(wrappedErr, ErrNotFound)) + + // 多层包装 + fmt.Printf(" 多层包装:\\n") + + baseErr := ErrNotFound + level1Err := fmt.Errorf("数据库查询失败: %w", baseErr) + level2Err := fmt.Errorf("用户服务错误: %w", level1Err) + level3Err := fmt.Errorf("API 请求失败: %w", level2Err) + + fmt.Printf(" 多层包装错误: %v\\n", level3Err) + fmt.Printf(" 是否包含 ErrNotFound: %t\\n", errors.Is(level3Err, ErrNotFound)) + + // 错误类型断言 (errors.As) + fmt.Printf(" 错误类型断言 (errors.As):\\n") + + customErr := &CustomError{ + Code: 404, + Message: "资源未找到", + Details: "请求的用户ID不存在", + } + + wrappedCustomErr := fmt.Errorf("处理请求失败: %w", customErr) + + var targetErr *CustomError + if errors.As(wrappedCustomErr, &targetErr) { + fmt.Printf(" 找到自定义错误: Code=%d, Message=%s\\n", + targetErr.Code, targetErr.Message) + } + + fmt.Println() +} + +// demonstrateErrorPatterns 演示错误处理模式 +func demonstrateErrorPatterns() { + fmt.Println("6. 错误处理模式:") + + // 哨兵错误模式 + fmt.Printf(" 哨兵错误模式:\\n") + + _, err := findUser("nonexistent") + if errors.Is(err, ErrUserNotFound) { + fmt.Printf(" 用户不存在,使用默认用户\\n") + } else if err != nil { + fmt.Printf(" 查找用户时发生其他错误: %v\\n", err) + } + + // 错误类型模式 + fmt.Printf(" 错误类型模式:\\n") + + err = performNetworkOperation() + var netErr *NetworkError + if errors.As(err, &netErr) { + if netErr.Temporary { + fmt.Printf(" 临时网络错误,可以重试: %v\\n", netErr) + } else { + fmt.Printf(" 永久网络错误: %v\\n", netErr) + } + } + + // 不透明错误模式 + fmt.Printf(" 不透明错误模式:\\n") + + err = callExternalAPI() + if err != nil { + fmt.Printf(" 外部API调用失败: %v\\n", err) + // 不检查具体错误类型,统一处理 + } + + // 错误聚合模式 + fmt.Printf(" 错误聚合模式:\\n") + + validator := NewValidator() + validator.ValidateRequired("name", "") + validator.ValidateEmail("email", "invalid-email") + validator.ValidateRange("age", -5, 0, 120) + + if validator.HasErrors() { + fmt.Printf(" 验证失败:\\n") + for _, err := range validator.Errors() { + fmt.Printf(" - %v\\n", err) + } + } + + // 错误恢复模式 + fmt.Printf(" 错误恢复模式:\\n") + + result := performWithFallback() + fmt.Printf(" 操作结果: %s\\n", result) + + // 错误重试模式 + fmt.Printf(" 错误重试模式:\\n") + + data, err := retryOperation(func() (string, error) { + // 模拟不稳定的操作 + if len(fmt.Sprintf("%d", rand.Int()))%3 == 0 { + return "成功数据", nil + } + return "", errors.New("临时失败") + }, 3) + + if err != nil { + fmt.Printf(" 重试操作最终失败: %v\\n", err) + } else { + fmt.Printf(" 重试操作成功: %s\\n", data) + } + + fmt.Println() +} + +// demonstratePracticalExamples 演示实际应用场景 +func demonstratePracticalExamples() { + fmt.Println("7. 实际应用场景:") + + // 文件操作错误处理 + fmt.Printf(" 文件操作错误处理:\\n") + + content, err := safeReadFile("config.json") + if err != nil { + fmt.Printf(" 读取配置文件失败: %v\\n", err) + } else { + fmt.Printf(" 配置内容: %s\\n", content) + } + + // 网络请求错误处理 + fmt.Printf(" 网络请求错误处理:\\n") + + response, err := httpGet("https://api.example.com/users/1") + if err != nil { + fmt.Printf(" HTTP请求失败: %v\\n", err) + } else { + fmt.Printf(" HTTP响应: %s\\n", response) + } + + // 数据库操作错误处理 + fmt.Printf(" 数据库操作错误处理:\\n") + + user := User{ID: 1, Name: "Alice", Email: "alice@example.com"} + err = saveUser(user) + if err != nil { + fmt.Printf(" 保存用户失败: %v\\n", err) + } else { + fmt.Printf(" 用户保存成功\\n") + } + + // JSON 解析错误处理 + fmt.Printf(" JSON 解析错误处理:\\n") + + jsonData := `{"name": "Bob", "age": "invalid"}` + user, err = parseUser(jsonData) + if err != nil { + fmt.Printf(" JSON解析失败: %v\\n", err) + } else { + fmt.Printf(" 解析用户: %+v\\n", user) + } + + // 业务逻辑错误处理 + fmt.Printf(" 业务逻辑错误处理:\\n") + + account := BankAccount{Balance: 100.0} + err = account.Withdraw(150.0) + if err != nil { + fmt.Printf(" 取款失败: %v\\n", err) + } else { + fmt.Printf(" 取款成功,余额: %.2f\\n", account.Balance) + } + + // 并发错误处理 + fmt.Printf(" 并发错误处理:\\n") + + results, errors := processConcurrently([]string{"task1", "task2", "error_task", "task4"}) + fmt.Printf(" 并发处理结果: %v\\n", results) + if len(errors) > 0 { + fmt.Printf(" 并发处理错误:\\n") + for i, err := range errors { + if err != nil { + fmt.Printf(" 任务%d错误: %v\\n", i, err) + } + } + } + + fmt.Println() +} + +// ========== 类型定义和辅助函数 ========== + +// 预定义错误 +var ( + ErrInvalidInput = errors.New("输入无效") + ErrNotFound = errors.New("未找到") + ErrPermissionDenied = errors.New("权限被拒绝") + ErrTimeout = errors.New("操作超时") + ErrUserNotFound = errors.New("用户未找到") +) + +// CustomError 自定义错误类型 +type CustomError struct { + Code int + Message string + Details string +} + +func (e *CustomError) Error() string { + return fmt.Sprintf("错误 %d: %s (%s)", e.Code, e.Message, e.Details) +} + +// NetworkError 网络错误类型 +type NetworkError struct { + Op string + URL string + Temporary bool + Err error +} + +func (e *NetworkError) Error() string { + return fmt.Sprintf("网络错误 %s %s: %v", e.Op, e.URL, e.Err) +} + +// User 用户结构 +type User struct { + ID int `json:"id"` + Name string `json:"name"` + Email string `json:"email"` + Age int `json:"age"` +} + +// BankAccount 银行账户 +type BankAccount struct { + Balance float64 +} + +func (ba *BankAccount) Withdraw(amount float64) error { + if amount <= 0 { + return fmt.Errorf("取款金额必须大于0,实际: %.2f", amount) + } + if amount > ba.Balance { + return fmt.Errorf("余额不足: 需要 %.2f,可用 %.2f", amount, ba.Balance) + } + ba.Balance -= amount + return nil +} + +// Validator 验证器 +type Validator struct { + errors []error +} + +func NewValidator() *Validator { + return &Validator{errors: make([]error, 0)} +} + +func (v *Validator) ValidateRequired(field, value string) { + if value == "" { + v.errors = append(v.errors, fmt.Errorf("字段 %s 是必需的", field)) + } +} + +func (v *Validator) ValidateEmail(field, value string) { + if value != "" && !strings.Contains(value, "@") { + v.errors = append(v.errors, fmt.Errorf("字段 %s 不是有效的邮箱地址", field)) + } +} + +func (v *Validator) ValidateRange(field string, value, min, max int) { + if value < min || value > max { + v.errors = append(v.errors, fmt.Errorf("字段 %s 必须在 %d 到 %d 之间,实际: %d", field, min, max, value)) + } +} + +func (v *Validator) HasErrors() bool { + return len(v.errors) > 0 +} + +func (v *Validator) Errors() []error { + return v.errors +} + +// ========== 辅助函数 ========== + +// divide 除法运算 +func divide(a, b float64) (float64, error) { + if b == 0 { + return 0, errors.New("除数不能为零") + } + return a / b, nil +} + +// validateAge 验证年龄 +func validateAge(age int) error { + if age < 0 { + return fmt.Errorf("年龄不能为负数: %d", age) + } + if age > 150 { + return fmt.Errorf("年龄不能超过150: %d", age) + } + return nil +} + +// readFile 读取文件 +func readFile(filename string) (string, error) { + // 模拟文件读取 + if filename == "example.txt" { + return "", fmt.Errorf("文件 %s 不存在", filename) + } + return "文件内容", nil +} + +// performMultipleOperations 执行多个操作 +func performMultipleOperations() error { + // 模拟多个操作 + operations := []func() error{ + func() error { return nil }, // 成功 + func() error { return nil }, // 成功 + func() error { return errors.New("第三个操作失败") }, // 失败 + } + + for i, op := range operations { + if err := op(); err != nil { + return fmt.Errorf("操作 %d 失败: %w", i+1, err) + } + } + return nil +} + +// handleSpecificError 处理特定错误 +func handleSpecificError(err error) { + if err == nil { + fmt.Printf("成功\\n") + return + } + + switch { + case errors.Is(err, ErrNotFound): + fmt.Printf("资源未找到\\n") + case errors.Is(err, ErrPermissionDenied): + fmt.Printf("权限不足\\n") + default: + fmt.Printf("未知错误: %v\\n", err) + } +} + +// fetchDataWithRetry 带重试的数据获取 +func fetchDataWithRetry(url string, maxRetries int) (string, error) { + var lastErr error + + for i := 0; i < maxRetries; i++ { + // 模拟网络请求 + if rand.Float32() < 0.3 { // 30% 成功率 + return fmt.Sprintf("数据来自 %s", url), nil + } + + lastErr = fmt.Errorf("请求 %s 失败 (尝试 %d/%d)", url, i+1, maxRetries) + time.Sleep(100 * time.Millisecond) // 重试延迟 + } + + return "", fmt.Errorf("重试 %d 次后仍然失败: %w", maxRetries, lastErr) +} + +// processBatch 批量处理 +func processBatch(items []string) ([]string, []error) { + var results []string + var errors []error + + for _, item := range items { + if item == "invalid" { + errors = append(errors, fmt.Errorf("无效项目: %s", item)) + } else { + results = append(results, fmt.Sprintf("处理后的%s", item)) + } + } + + return results, errors +} + +// calculateTotal 计算总和 +func calculateTotal(values []float64) (float64, error) { + total := 0.0 + for i, value := range values { + if value < 0 { + return 0, fmt.Errorf("索引 %d 的值不能为负数: %.2f", i, value) + } + total += value + } + return total, nil +} + +// getUserProfile 获取用户资料 +func getUserProfile(username string) (*User, error) { + // 模拟数据库查询 + if username == "nonexistent_user" { + return nil, fmt.Errorf("获取用户资料失败: %w", ErrUserNotFound) + } + + return &User{ + ID: 1, + Name: username, + Email: username + "@example.com", + }, nil +} + +// processOrder 处理订单 +func processOrder(orderID string) error { + // 模拟订单处理链 + if err := validateOrder(orderID); err != nil { + return fmt.Errorf("处理订单 %s 失败: %w", orderID, err) + } + return nil +} + +// validateOrder 验证订单 +func validateOrder(orderID string) error { + if orderID == "invalid_order_id" { + if err := checkOrderExists(orderID); err != nil { + return fmt.Errorf("订单验证失败: %w", err) + } + } + return nil +} + +// checkOrderExists 检查订单是否存在 +func checkOrderExists(orderID string) error { + return fmt.Errorf("数据库查询失败: %w", ErrNotFound) +} + +// printErrorChain 打印错误链 +func printErrorChain(err error, indent string) { + if err == nil { + return + } + + fmt.Printf("%s- %v\\n", indent, err) + + if unwrapped := errors.Unwrap(err); unwrapped != nil { + printErrorChain(unwrapped, indent+" ") + } +} + +// processItem 处理项目 +func processItem(item string) (string, error) { + switch item { + case "invalid": + return "", ErrInvalidInput + case "error": + return "", errors.New("处理错误") + default: + return fmt.Sprintf("处理后的%s", item), nil + } +} + +// findUser 查找用户 +func findUser(username string) (*User, error) { + if username == "nonexistent" { + return nil, ErrUserNotFound + } + return &User{Name: username}, nil +} + +// performNetworkOperation 执行网络操作 +func performNetworkOperation() error { + return &NetworkError{ + Op: "GET", + URL: "https://api.example.com", + Temporary: true, + Err: errors.New("连接超时"), + } +} + +// callExternalAPI 调用外部API +func callExternalAPI() error { + return errors.New("外部服务不可用") +} + +// performWithFallback 带回退的操作 +func performWithFallback() string { + // 尝试主要操作 + if err := primaryOperation(); err != nil { + // 主要操作失败,使用回退 + return fallbackOperation() + } + return "主要操作成功" +} + +// primaryOperation 主要操作 +func primaryOperation() error { + return errors.New("主要操作失败") +} + +// fallbackOperation 回退操作 +func fallbackOperation() string { + return "回退操作成功" +} + +// retryOperation 重试操作 +func retryOperation(op func() (string, error), maxRetries int) (string, error) { + var lastErr error + + for i := 0; i < maxRetries; i++ { + result, err := op() + if err == nil { + return result, nil + } + + lastErr = err + fmt.Printf(" 尝试 %d/%d 失败: %v\\n", i+1, maxRetries, err) + + if i < maxRetries-1 { + time.Sleep(100 * time.Millisecond) + } + } + + return "", fmt.Errorf("重试 %d 次后失败: %w", maxRetries, lastErr) +} + +// safeReadFile 安全读取文件 +func safeReadFile(filename string) (string, error) { + // 模拟文件读取 + switch filename { + case "config.json": + return "", fmt.Errorf("读取文件 %s 失败: %w", filename, os.ErrNotExist) + default: + return "文件内容", nil + } +} + +// httpGet HTTP GET 请求 +func httpGet(url string) (string, error) { + // 模拟HTTP请求 + if strings.Contains(url, "example.com") { + return "", &NetworkError{ + Op: "GET", + URL: url, + Temporary: false, + Err: errors.New("域名解析失败"), + } + } + return "HTTP响应内容", nil +} + +// saveUser 保存用户 +func saveUser(user User) error { + // 模拟数据库保存 + if user.Email == "" { + return fmt.Errorf("保存用户失败: %w", ErrInvalidInput) + } + return nil +} + +// parseUser 解析用户JSON +func parseUser(jsonData string) (User, error) { + var user User + if err := json.Unmarshal([]byte(jsonData), &user); err != nil { + return User{}, fmt.Errorf("解析用户JSON失败: %w", err) + } + return user, nil +} + +// processConcurrently 并发处理 +func processConcurrently(tasks []string) ([]string, []error) { + var wg sync.WaitGroup + results := make([]string, len(tasks)) + errors := make([]error, len(tasks)) + + for i, task := range tasks { + wg.Add(1) + go func(index int, taskName string) { + defer wg.Done() + + // 模拟任务处理 + if strings.Contains(taskName, "error") { + errors[index] = fmt.Errorf("任务 %s 处理失败", taskName) + } else { + results[index] = fmt.Sprintf("处理后的%s", taskName) + } + }(i, task) + } + + wg.Wait() + return results, errors +} + +/* +运行这个程序: +go run 01-basic-errors.go + +学习要点: +1. Go 语言使用显式错误处理,错误是值 +2. error 接口只有一个 Error() string 方法 +3. 使用多返回值模式处理错误 +4. 错误应该被检查和处理,不应该被忽略 +5. 错误信息应该清晰、有用、包含上下文 + +错误处理的特点: +1. 显式性:错误必须被显式检查 +2. 简单性:error 接口设计简单 +3. 组合性:错误可以被包装和组合 +4. 传播性:错误可以在调用栈中传播 +5. 灵活性:支持多种错误处理模式 + +错误创建方式: +1. errors.New():创建简单错误 +2. fmt.Errorf():创建格式化错误 +3. 自定义错误类型:实现 error 接口 +4. 预定义错误:定义常用错误变量 +5. 错误包装:使用 %w 动词包装错误 + +错误检查模式: +1. 立即检查:if err != nil { ... } +2. 错误传播:return err 或 return fmt.Errorf("...: %w", err) +3. 错误类型检查:errors.Is() 和 errors.As() +4. 错误恢复:提供默认值或回退方案 +5. 错误聚合:收集多个错误 + +错误处理模式: +1. 哨兵错误:预定义的错误值 +2. 错误类型:自定义错误结构体 +3. 不透明错误:不检查具体错误类型 +4. 错误包装:添加上下文信息 +5. 错误聚合:收集和批量处理错误 + +最佳实践: +1. 错误信息应该小写开头,不以标点结尾 +2. 错误信息应该包含足够的上下文 +3. 使用错误包装传播上下文 +4. 不要忽略错误,至少要记录日志 +5. 在适当的层级处理错误 + +常见陷阱: +1. 忽略错误返回值 +2. 错误信息不够清晰 +3. 过度包装错误 +4. 不适当的错误类型检查 +5. 在错误处理中引入新的错误 + +性能考虑: +1. 错误创建有一定开销 +2. 错误包装会增加内存使用 +3. 错误检查是必要的开销 +4. 避免在热点路径创建复杂错误 +5. 合理使用预定义错误 + +注意事项: +1. nil 错误表示没有错误 +2. 错误比较使用 == 或 errors.Is() +3. 错误类型断言使用 errors.As() +4. 错误包装使用 fmt.Errorf() 和 %w +5. 错误解包使用 errors.Unwrap() +*/ diff --git a/golang-learning/07-error-handling/02-custom-errors.go b/golang-learning/07-error-handling/02-custom-errors.go new file mode 100644 index 0000000..f27517e --- /dev/null +++ b/golang-learning/07-error-handling/02-custom-errors.go @@ -0,0 +1,1071 @@ +/* +02-custom-errors.go - Go 语言自定义错误详解 + +学习目标: +1. 理解自定义错误的必要性 +2. 掌握自定义错误类型的设计 +3. 学会实现 error 接口 +4. 了解错误的分类和层次 +5. 掌握错误的序列化和反序列化 + +知识点: +- 自定义错误类型的设计 +- 实现 error 接口 +- 错误的分类和层次结构 +- 错误的附加信息 +- 错误的序列化 +- 错误的本地化 +*/ + +package main + +import ( + "encoding/json" + "fmt" + "net/http" + "strings" + "time" +) + +func main() { + fmt.Println("=== Go 语言自定义错误详解 ===\\n") + + // 演示基本自定义错误 + demonstrateBasicCustomErrors() + + // 演示结构化错误 + demonstrateStructuredErrors() + + // 演示错误分类 + demonstrateErrorClassification() + + // 演示错误层次结构 + demonstrateErrorHierarchy() + + // 演示错误的附加信息 + demonstrateErrorWithDetails() + + // 演示错误的序列化 + demonstrateErrorSerialization() + + // 演示实际应用场景 + demonstratePracticalCustomErrors() +} + +// demonstrateBasicCustomErrors 演示基本自定义错误 +func demonstrateBasicCustomErrors() { + fmt.Println("1. 基本自定义错误:") + + // 简单自定义错误 + fmt.Printf(" 简单自定义错误:\\n") + + err := &SimpleError{Message: "这是一个简单的自定义错误"} + fmt.Printf(" 错误: %v\\n", err) + fmt.Printf(" 错误类型: %T\\n", err) + + // 带代码的错误 + fmt.Printf(" 带代码的错误:\\n") + + codeErr := &CodeError{ + Code: 1001, + Message: "用户输入无效", + } + fmt.Printf(" 错误: %v\\n", codeErr) + fmt.Printf(" 错误代码: %d\\n", codeErr.Code) + + // 带时间戳的错误 + fmt.Printf(" 带时间戳的错误:\\n") + + timeErr := &TimestampError{ + Message: "操作失败", + Timestamp: time.Now(), + } + fmt.Printf(" 错误: %v\\n", timeErr) + + // 带上下文的错误 + fmt.Printf(" 带上下文的错误:\\n") + + contextErr := &ContextError{ + Operation: "数据库查询", + Resource: "用户表", + Message: "连接超时", + } + fmt.Printf(" 错误: %v\\n", contextErr) + + fmt.Println() +} + +// demonstrateStructuredErrors 演示结构化错误 +func demonstrateStructuredErrors() { + fmt.Println("2. 结构化错误:") + + // 验证错误 + fmt.Printf(" 验证错误:\\n") + + validationErr := &ValidationError{ + Field: "email", + Value: "invalid-email", + Rule: "email_format", + Message: "邮箱格式不正确", + } + fmt.Printf(" 验证错误: %v\\n", validationErr) + + // HTTP 错误 + fmt.Printf(" HTTP 错误:\\n") + + httpErr := &HTTPError{ + StatusCode: http.StatusNotFound, + Method: "GET", + URL: "/api/users/999", + Message: "用户不存在", + } + fmt.Printf(" HTTP错误: %v\\n", httpErr) + fmt.Printf(" 状态码: %d\\n", httpErr.StatusCode) + fmt.Printf(" 是否客户端错误: %t\\n", httpErr.IsClientError()) + fmt.Printf(" 是否服务器错误: %t\\n", httpErr.IsServerError()) + + // 数据库错误 + fmt.Printf(" 数据库错误:\\n") + + dbErr := &DatabaseError{ + Operation: "INSERT", + Table: "users", + Query: "INSERT INTO users (name, email) VALUES (?, ?)", + SQLState: "23000", + Message: "重复键值违反唯一约束", + } + fmt.Printf(" 数据库错误: %v\\n", dbErr) + fmt.Printf(" 是否约束违反: %t\\n", dbErr.IsConstraintViolation()) + + // 业务逻辑错误 + fmt.Printf(" 业务逻辑错误:\\n") + + businessErr := &BusinessError{ + Domain: "用户管理", + Rule: "年龄限制", + Message: "用户年龄必须在18-65岁之间", + Severity: "ERROR", + Retryable: false, + } + fmt.Printf(" 业务错误: %v\\n", businessErr) + fmt.Printf(" 可重试: %t\\n", businessErr.Retryable) + + fmt.Println() +} + +// demonstrateErrorClassification 演示错误分类 +func demonstrateErrorClassification() { + fmt.Println("3. 错误分类:") + + // 临时错误 vs 永久错误 + fmt.Printf(" 临时错误 vs 永久错误:\\n") + + tempErr := &TemporaryError{ + Message: "网络连接超时", + Temporary: true, + RetryAfter: 5 * time.Second, + } + fmt.Printf(" 临时错误: %v\\n", tempErr) + fmt.Printf(" 是否临时: %t\\n", tempErr.IsTemporary()) + fmt.Printf(" 重试间隔: %v\\n", tempErr.RetryAfter) + + permErr := &PermanentError{ + Message: "认证失败:无效的API密钥", + Reason: "INVALID_CREDENTIALS", + } + fmt.Printf(" 永久错误: %v\\n", permErr) + fmt.Printf(" 是否临时: %t\\n", permErr.IsTemporary()) + + // 可恢复错误 vs 不可恢复错误 + fmt.Printf(" 可恢复错误 vs 不可恢复错误:\\n") + + recoverableErr := &RecoverableError{ + Message: "磁盘空间不足", + RecoveryHint: "请清理磁盘空间后重试", + } + fmt.Printf(" 可恢复错误: %v\\n", recoverableErr) + fmt.Printf(" 恢复提示: %s\\n", recoverableErr.RecoveryHint) + + fatalErr := &FatalError{ + Message: "系统内存不足,程序无法继续运行", + Cause: "OUT_OF_MEMORY", + } + fmt.Printf(" 致命错误: %v\\n", fatalErr) + + // 用户错误 vs 系统错误 + fmt.Printf(" 用户错误 vs 系统错误:\\n") + + userErr := &UserError{ + Message: "密码长度至少8位", + UserMessage: "请输入至少8位字符的密码", + Field: "password", + } + fmt.Printf(" 用户错误: %v\\n", userErr) + fmt.Printf(" 用户友好消息: %s\\n", userErr.UserMessage) + + systemErr := &SystemError{ + Message: "数据库连接池耗尽", + Component: "database", + Level: "CRITICAL", + } + fmt.Printf(" 系统错误: %v\\n", systemErr) + fmt.Printf(" 组件: %s\\n", systemErr.Component) + + fmt.Println() +} + +// demonstrateErrorHierarchy 演示错误层次结构 +func demonstrateErrorHierarchy() { + fmt.Println("4. 错误层次结构:") + + // 基础错误接口 + fmt.Printf(" 基础错误接口:\\n") + + var err error + + // 网络错误层次 + err = &NetworkError{ + BaseError: BaseError{ + Code: "NET001", + Message: "网络连接失败", + Timestamp: time.Now(), + }, + Host: "api.example.com", + Port: 443, + Timeout: 30 * time.Second, + } + + fmt.Printf(" 网络错误: %v\\n", err) + + // 检查错误类型 + if netErr, ok := err.(*NetworkError); ok { + fmt.Printf(" 主机: %s\\n", netErr.Host) + fmt.Printf(" 端口: %d\\n", netErr.Port) + fmt.Printf(" 超时: %v\\n", netErr.Timeout) + } + + // 应用错误层次 + err = &ApplicationError{ + BaseError: BaseError{ + Code: "APP001", + Message: "应用程序错误", + Timestamp: time.Now(), + }, + Module: "用户服务", + Version: "1.2.3", + Stack: []string{"main.go:42", "user.go:15", "db.go:89"}, + } + + fmt.Printf(" 应用错误: %v\\n", err) + + if appErr, ok := err.(*ApplicationError); ok { + fmt.Printf(" 模块: %s\\n", appErr.Module) + fmt.Printf(" 版本: %s\\n", appErr.Version) + fmt.Printf(" 调用栈: %v\\n", appErr.Stack) + } + + // 错误链 + fmt.Printf(" 错误链:\\n") + + rootErr := &BaseError{ + Code: "DB001", + Message: "数据库连接失败", + } + + serviceErr := &ServiceError{ + BaseError: BaseError{ + Code: "SVC001", + Message: "服务调用失败", + }, + Service: "用户服务", + Cause: rootErr, + } + + apiErr := &APIError{ + BaseError: BaseError{ + Code: "API001", + Message: "API请求失败", + }, + Endpoint: "/api/users", + Cause: serviceErr, + } + + fmt.Printf(" API错误链: %v\\n", apiErr) + printErrorChain(apiErr, " ") + + fmt.Println() +} + +// demonstrateErrorWithDetails 演示错误的附加信息 +func demonstrateErrorWithDetails() { + fmt.Println("5. 错误的附加信息:") + + // 带详细信息的错误 + fmt.Printf(" 带详细信息的错误:\\n") + + detailedErr := &DetailedError{ + Code: "VALIDATION_FAILED", + Message: "数据验证失败", + Details: map[string]interface{}{ + "field": "age", + "value": -5, + "constraint": "must be positive", + "suggested_fix": "请输入正数", + "documentation": "https://docs.example.com/validation", + }, + } + + fmt.Printf(" 详细错误: %v\\n", detailedErr) + fmt.Printf(" 详细信息:\\n") + for key, value := range detailedErr.Details { + fmt.Printf(" %s: %v\\n", key, value) + } + + // 带元数据的错误 + fmt.Printf(" 带元数据的错误:\\n") + + metaErr := &MetadataError{ + Message: "文件处理失败", + Metadata: ErrorMetadata{ + RequestID: "req-12345", + UserID: "user-67890", + SessionID: "sess-abcdef", + TraceID: "trace-xyz789", + Environment: "production", + Version: "v1.0.0", + }, + } + + fmt.Printf(" 元数据错误: %v\\n", metaErr) + fmt.Printf(" 请求ID: %s\\n", metaErr.Metadata.RequestID) + fmt.Printf(" 用户ID: %s\\n", metaErr.Metadata.UserID) + fmt.Printf(" 环境: %s\\n", metaErr.Metadata.Environment) + + // 带建议的错误 + fmt.Printf(" 带建议的错误:\\n") + + suggestErr := &SuggestedError{ + Message: "配置文件格式错误", + Suggestions: []string{ + "检查JSON语法是否正确", + "确保所有字符串都用双引号包围", + "验证配置文件的结构", + "参考示例配置文件", + }, + HelpURL: "https://docs.example.com/config", + } + + fmt.Printf(" 建议错误: %v\\n", suggestErr) + fmt.Printf(" 建议:\\n") + for i, suggestion := range suggestErr.Suggestions { + fmt.Printf(" %d. %s\\n", i+1, suggestion) + } + fmt.Printf(" 帮助链接: %s\\n", suggestErr.HelpURL) + + fmt.Println() +} + +// demonstrateErrorSerialization 演示错误的序列化 +func demonstrateErrorSerialization() { + fmt.Println("6. 错误的序列化:") + + // JSON 序列化 + fmt.Printf(" JSON 序列化:\\n") + + serializableErr := &SerializableError{ + Code: "ERR001", + Message: "操作失败", + Timestamp: time.Now(), + Details: map[string]interface{}{ + "operation": "user_create", + "reason": "duplicate_email", + "email": "user@example.com", + }, + } + + // 序列化为JSON + jsonData, err := json.MarshalIndent(serializableErr, "", " ") + if err != nil { + fmt.Printf(" 序列化失败: %v\\n", err) + } else { + fmt.Printf(" JSON序列化结果:\\n%s\\n", string(jsonData)) + } + + // 从JSON反序列化 + var deserializedErr SerializableError + err = json.Unmarshal(jsonData, &deserializedErr) + if err != nil { + fmt.Printf(" 反序列化失败: %v\\n", err) + } else { + fmt.Printf(" 反序列化结果: %v\\n", &deserializedErr) + } + + // 错误传输 + fmt.Printf(" 错误传输:\\n") + + transportErr := &TransportError{ + ID: "err-12345", + Type: "ValidationError", + Message: "输入验证失败", + Code: 400, + Timestamp: time.Now().Unix(), + Data: map[string]interface{}{ + "field": "email", + "value": "invalid", + }, + } + + // 模拟网络传输 + transmitted := transmitError(transportErr) + fmt.Printf(" 传输的错误: %v\\n", transmitted) + + // 错误本地化 + fmt.Printf(" 错误本地化:\\n") + + localizedErr := &LocalizedError{ + Code: "USER_NOT_FOUND", + Message: "User not found", + Locale: "en", + Translations: map[string]string{ + "en": "User not found", + "zh": "用户未找到", + "ja": "ユーザーが見つかりません", + "fr": "Utilisateur non trouvé", + }, + } + + fmt.Printf(" 英文: %s\\n", localizedErr.GetMessage("en")) + fmt.Printf(" 中文: %s\\n", localizedErr.GetMessage("zh")) + fmt.Printf(" 日文: %s\\n", localizedErr.GetMessage("ja")) + fmt.Printf(" 法文: %s\\n", localizedErr.GetMessage("fr")) + fmt.Printf(" 默认: %s\\n", localizedErr.GetMessage("unknown")) + + fmt.Println() +} + +// demonstratePracticalCustomErrors 演示实际应用场景 +func demonstratePracticalCustomErrors() { + fmt.Println("7. 实际应用场景:") + + // Web API 错误处理 + fmt.Printf(" Web API 错误处理:\\n") + + apiErrors := []error{ + &APIError{ + BaseError: BaseError{Code: "AUTH001", Message: "认证失败"}, + Endpoint: "/api/login", + }, + &APIError{ + BaseError: BaseError{Code: "RATE001", Message: "请求频率超限"}, + Endpoint: "/api/data", + }, + &APIError{ + BaseError: BaseError{Code: "VAL001", Message: "参数验证失败"}, + Endpoint: "/api/users", + }, + } + + for _, err := range apiErrors { + handleAPIError(err) + } + + // 数据库操作错误 + fmt.Printf(" 数据库操作错误:\\n") + + dbErrors := []error{ + &DatabaseError{ + Operation: "SELECT", + Table: "users", + SQLState: "42000", + Message: "语法错误", + }, + &DatabaseError{ + Operation: "INSERT", + Table: "orders", + SQLState: "23505", + Message: "唯一约束违反", + }, + &DatabaseError{ + Operation: "UPDATE", + Table: "products", + SQLState: "40001", + Message: "死锁检测", + }, + } + + for _, err := range dbErrors { + handleDatabaseError(err) + } + + // 文件操作错误 + fmt.Printf(" 文件操作错误:\\n") + + fileErr := &FileError{ + Operation: "read", + Path: "/etc/config.json", + Message: "权限被拒绝", + OSError: "permission denied", + } + + handleFileError(fileErr) + + // 业务规则错误 + fmt.Printf(" 业务规则错误:\\n") + + businessErrors := []*BusinessRuleError{ + { + Rule: "最小订单金额", + Description: "订单金额必须大于100元", + Value: "50", + Constraint: "> 100", + }, + { + Rule: "库存检查", + Description: "商品库存不足", + Value: "2", + Constraint: ">= 5", + }, + } + + for _, err := range businessErrors { + fmt.Printf(" 业务规则违反: %v\\n", err) + } + + // 集成错误处理 + fmt.Printf(" 集成错误处理:\\n") + + integrationErr := &IntegrationError{ + Service: "支付服务", + Endpoint: "https://pay.example.com/api/charge", + Method: "POST", + StatusCode: 503, + Message: "服务不可用", + RetryAfter: 30 * time.Second, + Recoverable: true, + } + + fmt.Printf(" 集成错误: %v\\n", integrationErr) + fmt.Printf(" 可恢复: %t\\n", integrationErr.Recoverable) + fmt.Printf(" 重试间隔: %v\\n", integrationErr.RetryAfter) + + fmt.Println() +} + +// ========== 自定义错误类型定义 ========== + +// SimpleError 简单自定义错误 +type SimpleError struct { + Message string +} + +func (e *SimpleError) Error() string { + return e.Message +} + +// CodeError 带代码的错误 +type CodeError struct { + Code int + Message string +} + +func (e *CodeError) Error() string { + return fmt.Sprintf("[%d] %s", e.Code, e.Message) +} + +// TimestampError 带时间戳的错误 +type TimestampError struct { + Message string + Timestamp time.Time +} + +func (e *TimestampError) Error() string { + return fmt.Sprintf("%s (发生时间: %s)", e.Message, e.Timestamp.Format("2006-01-02 15:04:05")) +} + +// ContextError 带上下文的错误 +type ContextError struct { + Operation string + Resource string + Message string +} + +func (e *ContextError) Error() string { + return fmt.Sprintf("操作 '%s' 在资源 '%s' 上失败: %s", e.Operation, e.Resource, e.Message) +} + +// ValidationError 验证错误 +type ValidationError struct { + Field string + Value string + Rule string + Message string +} + +func (e *ValidationError) Error() string { + return fmt.Sprintf("字段 '%s' 验证失败 (值: '%s', 规则: %s): %s", + e.Field, e.Value, e.Rule, e.Message) +} + +// HTTPError HTTP错误 +type HTTPError struct { + StatusCode int + Method string + URL string + Message string +} + +func (e *HTTPError) Error() string { + return fmt.Sprintf("HTTP %d: %s %s - %s", e.StatusCode, e.Method, e.URL, e.Message) +} + +func (e *HTTPError) IsClientError() bool { + return e.StatusCode >= 400 && e.StatusCode < 500 +} + +func (e *HTTPError) IsServerError() bool { + return e.StatusCode >= 500 && e.StatusCode < 600 +} + +// DatabaseError 数据库错误 +type DatabaseError struct { + Operation string + Table string + Query string + SQLState string + Message string +} + +func (e *DatabaseError) Error() string { + return fmt.Sprintf("数据库错误 [%s]: %s 操作在表 '%s' 上失败 - %s", + e.SQLState, e.Operation, e.Table, e.Message) +} + +func (e *DatabaseError) IsConstraintViolation() bool { + return strings.HasPrefix(e.SQLState, "23") +} + +// BusinessError 业务逻辑错误 +type BusinessError struct { + Domain string + Rule string + Message string + Severity string + Retryable bool +} + +func (e *BusinessError) Error() string { + return fmt.Sprintf("业务错误 [%s]: 规则 '%s' 违反 - %s", e.Domain, e.Rule, e.Message) +} + +// TemporaryError 临时错误 +type TemporaryError struct { + Message string + Temporary bool + RetryAfter time.Duration +} + +func (e *TemporaryError) Error() string { + return e.Message +} + +func (e *TemporaryError) IsTemporary() bool { + return e.Temporary +} + +// PermanentError 永久错误 +type PermanentError struct { + Message string + Reason string +} + +func (e *PermanentError) Error() string { + return fmt.Sprintf("%s (原因: %s)", e.Message, e.Reason) +} + +func (e *PermanentError) IsTemporary() bool { + return false +} + +// RecoverableError 可恢复错误 +type RecoverableError struct { + Message string + RecoveryHint string +} + +func (e *RecoverableError) Error() string { + return e.Message +} + +// FatalError 致命错误 +type FatalError struct { + Message string + Cause string +} + +func (e *FatalError) Error() string { + return fmt.Sprintf("致命错误: %s (原因: %s)", e.Message, e.Cause) +} + +// UserError 用户错误 +type UserError struct { + Message string + UserMessage string + Field string +} + +func (e *UserError) Error() string { + return e.Message +} + +// SystemError 系统错误 +type SystemError struct { + Message string + Component string + Level string +} + +func (e *SystemError) Error() string { + return fmt.Sprintf("系统错误 [%s/%s]: %s", e.Component, e.Level, e.Message) +} + +// BaseError 基础错误 +type BaseError struct { + Code string + Message string + Timestamp time.Time +} + +func (e *BaseError) Error() string { + return fmt.Sprintf("[%s] %s", e.Code, e.Message) +} + +// NetworkError 网络错误 +type NetworkError struct { + BaseError + Host string + Port int + Timeout time.Duration +} + +func (e *NetworkError) Error() string { + return fmt.Sprintf("网络错误 [%s]: 连接 %s:%d 失败 - %s (超时: %v)", + e.Code, e.Host, e.Port, e.Message, e.Timeout) +} + +// ApplicationError 应用错误 +type ApplicationError struct { + BaseError + Module string + Version string + Stack []string +} + +func (e *ApplicationError) Error() string { + return fmt.Sprintf("应用错误 [%s]: 模块 '%s' v%s - %s", + e.Code, e.Module, e.Version, e.Message) +} + +// ServiceError 服务错误 +type ServiceError struct { + BaseError + Service string + Cause error +} + +func (e *ServiceError) Error() string { + if e.Cause != nil { + return fmt.Sprintf("服务错误 [%s]: 服务 '%s' - %s (原因: %v)", + e.Code, e.Service, e.Message, e.Cause) + } + return fmt.Sprintf("服务错误 [%s]: 服务 '%s' - %s", e.Code, e.Service, e.Message) +} + +func (e *ServiceError) Unwrap() error { + return e.Cause +} + +// APIError API错误 +type APIError struct { + BaseError + Endpoint string + Cause error +} + +func (e *APIError) Error() string { + if e.Cause != nil { + return fmt.Sprintf("API错误 [%s]: 端点 '%s' - %s (原因: %v)", + e.Code, e.Endpoint, e.Message, e.Cause) + } + return fmt.Sprintf("API错误 [%s]: 端点 '%s' - %s", e.Code, e.Endpoint, e.Message) +} + +func (e *APIError) Unwrap() error { + return e.Cause +} + +// DetailedError 带详细信息的错误 +type DetailedError struct { + Code string + Message string + Details map[string]interface{} +} + +func (e *DetailedError) Error() string { + return fmt.Sprintf("[%s] %s", e.Code, e.Message) +} + +// ErrorMetadata 错误元数据 +type ErrorMetadata struct { + RequestID string `json:"request_id"` + UserID string `json:"user_id"` + SessionID string `json:"session_id"` + TraceID string `json:"trace_id"` + Environment string `json:"environment"` + Version string `json:"version"` +} + +// MetadataError 带元数据的错误 +type MetadataError struct { + Message string + Metadata ErrorMetadata +} + +func (e *MetadataError) Error() string { + return fmt.Sprintf("%s [请求ID: %s]", e.Message, e.Metadata.RequestID) +} + +// SuggestedError 带建议的错误 +type SuggestedError struct { + Message string + Suggestions []string + HelpURL string +} + +func (e *SuggestedError) Error() string { + return e.Message +} + +// SerializableError 可序列化错误 +type SerializableError struct { + Code string `json:"code"` + Message string `json:"message"` + Timestamp time.Time `json:"timestamp"` + Details map[string]interface{} `json:"details,omitempty"` +} + +func (e *SerializableError) Error() string { + return fmt.Sprintf("[%s] %s", e.Code, e.Message) +} + +// TransportError 传输错误 +type TransportError struct { + ID string `json:"id"` + Type string `json:"type"` + Message string `json:"message"` + Code int `json:"code"` + Timestamp int64 `json:"timestamp"` + Data map[string]interface{} `json:"data,omitempty"` +} + +func (e *TransportError) Error() string { + return fmt.Sprintf("[%s] %s: %s", e.ID, e.Type, e.Message) +} + +// LocalizedError 本地化错误 +type LocalizedError struct { + Code string + Message string + Locale string + Translations map[string]string +} + +func (e *LocalizedError) Error() string { + return e.Message +} + +func (e *LocalizedError) GetMessage(locale string) string { + if msg, ok := e.Translations[locale]; ok { + return msg + } + return e.Message // 返回默认消息 +} + +// FileError 文件错误 +type FileError struct { + Operation string + Path string + Message string + OSError string +} + +func (e *FileError) Error() string { + return fmt.Sprintf("文件操作 '%s' 在路径 '%s' 失败: %s (%s)", + e.Operation, e.Path, e.Message, e.OSError) +} + +// BusinessRuleError 业务规则错误 +type BusinessRuleError struct { + Rule string + Description string + Value string + Constraint string +} + +func (e *BusinessRuleError) Error() string { + return fmt.Sprintf("业务规则 '%s' 违反: %s (值: %s, 约束: %s)", + e.Rule, e.Description, e.Value, e.Constraint) +} + +// IntegrationError 集成错误 +type IntegrationError struct { + Service string + Endpoint string + Method string + StatusCode int + Message string + RetryAfter time.Duration + Recoverable bool +} + +func (e *IntegrationError) Error() string { + return fmt.Sprintf("集成错误: %s %s %s 返回 %d - %s", + e.Service, e.Method, e.Endpoint, e.StatusCode, e.Message) +} + +// ========== 辅助函数 ========== + +// printErrorChain 打印错误链 +func printErrorChain(err error, indent string) { + if err == nil { + return + } + + fmt.Printf("%s- %v\\n", indent, err) + + // 检查是否有 Unwrap 方法 + if unwrapper, ok := err.(interface{ Unwrap() error }); ok { + if cause := unwrapper.Unwrap(); cause != nil { + printErrorChain(cause, indent+" ") + } + } +} + +// transmitError 模拟错误传输 +func transmitError(err *TransportError) *TransportError { + // 模拟网络传输过程 + return &TransportError{ + ID: err.ID, + Type: err.Type, + Message: err.Message, + Code: err.Code, + Timestamp: err.Timestamp, + Data: err.Data, + } +} + +// handleAPIError 处理API错误 +func handleAPIError(err error) { + if apiErr, ok := err.(*APIError); ok { + switch apiErr.Code { + case "AUTH001": + fmt.Printf(" 认证错误,需要重新登录\\n") + case "RATE001": + fmt.Printf(" 请求频率超限,需要等待\\n") + case "VAL001": + fmt.Printf(" 参数验证失败,检查输入\\n") + default: + fmt.Printf(" 未知API错误: %v\\n", apiErr) + } + } +} + +// handleDatabaseError 处理数据库错误 +func handleDatabaseError(err error) { + if dbErr, ok := err.(*DatabaseError); ok { + switch { + case strings.HasPrefix(dbErr.SQLState, "42"): + fmt.Printf(" SQL语法错误: %v\\n", dbErr) + case strings.HasPrefix(dbErr.SQLState, "23"): + fmt.Printf(" 约束违反错误: %v\\n", dbErr) + case strings.HasPrefix(dbErr.SQLState, "40"): + fmt.Printf(" 事务错误: %v\\n", dbErr) + default: + fmt.Printf(" 其他数据库错误: %v\\n", dbErr) + } + } +} + +// handleFileError 处理文件错误 +func handleFileError(err *FileError) { + fmt.Printf(" 文件错误: %v\\n", err) + + switch err.Operation { + case "read": + fmt.Printf(" 建议: 检查文件是否存在和读取权限\\n") + case "write": + fmt.Printf(" 建议: 检查目录写入权限和磁盘空间\\n") + case "delete": + fmt.Printf(" 建议: 检查文件是否被其他程序占用\\n") + } +} + +/* +运行这个程序: +go run 02-custom-errors.go + +学习要点: +1. 自定义错误类型通过实现 error 接口来创建 +2. 自定义错误可以包含更多的上下文信息 +3. 错误可以按照不同的维度进行分类 +4. 错误层次结构有助于组织和处理复杂的错误情况 +5. 错误的序列化和本地化对于分布式系统很重要 + +自定义错误的优势: +1. 提供更多的上下文信息 +2. 支持错误分类和层次结构 +3. 便于错误处理和恢复 +4. 支持错误的序列化和传输 +5. 提供更好的用户体验 + +错误设计原则: +1. 错误信息应该清晰、准确 +2. 包含足够的上下文信息 +3. 支持错误的分类和处理 +4. 考虑错误的传播和包装 +5. 提供恢复建议和帮助信息 + +错误分类维度: +1. 临时性:临时错误 vs 永久错误 +2. 可恢复性:可恢复错误 vs 不可恢复错误 +3. 责任方:用户错误 vs 系统错误 +4. 严重程度:警告 vs 错误 vs 致命错误 +5. 来源:网络错误 vs 数据库错误 vs 业务错误 + +错误层次结构: +1. 基础错误:定义通用的错误属性 +2. 分类错误:按照错误类型分类 +3. 具体错误:特定场景的错误实现 +4. 错误链:支持错误的嵌套和包装 +5. 错误接口:定义错误的行为 + +实际应用考虑: +1. 错误码的设计和管理 +2. 错误信息的国际化 +3. 错误的日志记录 +4. 错误的监控和告警 +5. 错误的用户友好展示 + +最佳实践: +1. 为不同的错误场景定义专门的错误类型 +2. 在错误中包含足够的上下文信息 +3. 支持错误的包装和解包 +4. 提供错误的分类和判断方法 +5. 考虑错误的序列化和传输需求 + +注意事项: +1. 避免错误信息中包含敏感信息 +2. 错误类型不要过于复杂 +3. 保持错误接口的一致性 +4. 考虑错误的性能影响 +5. 提供适当的错误恢复机制 +*/ diff --git a/golang-learning/07-error-handling/03-panic-recover.go b/golang-learning/07-error-handling/03-panic-recover.go new file mode 100644 index 0000000..1801351 --- /dev/null +++ b/golang-learning/07-error-handling/03-panic-recover.go @@ -0,0 +1,941 @@ +/* +03-panic-recover.go - Go 语言 Panic 和 Recover 详解 + +学习目标: +1. 理解 panic 的概念和使用场景 +2. 掌握 recover 的恢复机制 +3. 学会 defer 与 panic/recover 的配合 +4. 了解 panic 的传播机制 +5. 掌握 panic/recover 的最佳实践 + +知识点: +- panic 的触发条件和行为 +- recover 的恢复机制 +- defer 语句的执行顺序 +- panic 的传播和栈展开 +- panic/recover 的实际应用 +- 错误处理 vs panic 的选择 +*/ + +package main + +import ( + "fmt" + "runtime" + "strconv" + "time" +) + +func main() { + fmt.Println("=== Go 语言 Panic 和 Recover 详解 ===\\n") + + // 演示 panic 的基本概念 + demonstratePanicBasics() + + // 演示 recover 的使用 + demonstrateRecover() + + // 演示 defer 与 panic/recover 的配合 + demonstrateDeferWithPanicRecover() + + // 演示 panic 的传播 + demonstratePanicPropagation() + + // 演示 panic/recover 的实际应用 + demonstratePracticalUsage() + + // 演示最佳实践 + demonstrateBestPractices() + + // 演示错误处理 vs panic 的选择 + demonstrateErrorVsPanic() +} + +// demonstratePanicBasics 演示 panic 的基本概念 +func demonstratePanicBasics() { + fmt.Println("1. Panic 的基本概念:") + + // panic 的基本特性 + fmt.Printf(" Panic 的基本特性:\\n") + fmt.Printf(" - panic 是运行时错误,会导致程序崩溃\\n") + fmt.Printf(" - panic 会停止当前函数的执行\\n") + fmt.Printf(" - panic 会执行当前函数的 defer 语句\\n") + fmt.Printf(" - panic 会向上传播到调用栈\\n") + fmt.Printf(" - panic 可以被 recover 捕获\\n") + + // 手动触发 panic + fmt.Printf(" 手动触发 panic:\\n") + + func() { + defer func() { + if r := recover(); r != nil { + fmt.Printf(" 捕获到 panic: %v\\n", r) + } + }() + + fmt.Printf(" 准备触发 panic\\n") + panic("这是一个手动触发的 panic") + fmt.Printf(" 这行代码不会执行\\n") + }() + + // 常见的 panic 场景 + fmt.Printf(" 常见的 panic 场景:\\n") + + // 1. 数组越界 + func() { + defer func() { + if r := recover(); r != nil { + fmt.Printf(" 数组越界 panic: %v\\n", r) + } + }() + + arr := [3]int{1, 2, 3} + fmt.Printf(" 访问数组索引 5: %d\\n", arr[5]) // 会 panic + }() + + // 2. 空指针解引用 + func() { + defer func() { + if r := recover(); r != nil { + fmt.Printf(" 空指针解引用 panic: %v\\n", r) + } + }() + + var ptr *int + fmt.Printf(" 解引用空指针: %d\\n", *ptr) // 会 panic + }() + + // 3. 类型断言失败 + func() { + defer func() { + if r := recover(); r != nil { + fmt.Printf(" 类型断言失败 panic: %v\\n", r) + } + }() + + var x interface{} = "hello" + num := x.(int) // 会 panic + fmt.Printf(" 类型断言结果: %d\\n", num) + }() + + // 4. 向已关闭的 channel 发送数据 + func() { + defer func() { + if r := recover(); r != nil { + fmt.Printf(" 向已关闭 channel 发送数据 panic: %v\\n", r) + } + }() + + ch := make(chan int) + close(ch) + ch <- 1 // 会 panic + }() + + fmt.Println() +} + +// demonstrateRecover 演示 recover 的使用 +func demonstrateRecover() { + fmt.Println("2. Recover 的使用:") + + // recover 的基本概念 + fmt.Printf(" Recover 的基本概念:\\n") + fmt.Printf(" - recover 只能在 defer 函数中使用\\n") + fmt.Printf(" - recover 可以捕获当前 goroutine 的 panic\\n") + fmt.Printf(" - recover 返回 panic 的值\\n") + fmt.Printf(" - recover 后程序可以继续执行\\n") + + // 基本 recover 示例 + fmt.Printf(" 基本 recover 示例:\\n") + + result := safeFunction(func() int { + panic("计算过程中发生错误") + return 42 + }) + fmt.Printf(" 安全函数返回: %d\\n", result) + + // recover 的返回值 + fmt.Printf(" recover 的返回值:\\n") + + func() { + defer func() { + if r := recover(); r != nil { + fmt.Printf(" panic 值: %v\\n", r) + fmt.Printf(" panic 类型: %T\\n", r) + + // 根据 panic 类型进行不同处理 + switch v := r.(type) { + case string: + fmt.Printf(" 字符串 panic: %s\\n", v) + case int: + fmt.Printf(" 整数 panic: %d\\n", v) + case error: + fmt.Printf(" 错误 panic: %v\\n", v) + default: + fmt.Printf(" 其他类型 panic: %v\\n", v) + } + } + }() + + // 触发不同类型的 panic + testPanics := []interface{}{ + "字符串错误", + 42, + fmt.Errorf("错误对象"), + struct{ Message string }{"结构体错误"}, + } + + for i, panicValue := range testPanics { + func() { + defer func() { + if r := recover(); r != nil { + fmt.Printf(" 测试 %d - panic: %v (%T)\\n", i+1, r, r) + } + }() + panic(panicValue) + }() + } + }() + + // recover 的条件 + fmt.Printf(" recover 的条件:\\n") + + // 正确的 recover 使用 + func() { + defer func() { + if r := recover(); r != nil { + fmt.Printf(" 正确捕获 panic: %v\\n", r) + } + }() + panic("正确的 recover 示例") + }() + + // 错误的 recover 使用 + func() { + defer func() { + // 这个 recover 不会捕获到 panic,因为不是直接在 defer 中调用 + go func() { + if r := recover(); r != nil { + fmt.Printf(" 错误的 recover: %v\\n", r) + } + }() + }() + + defer func() { + if r := recover(); r != nil { + fmt.Printf(" 正确捕获嵌套 panic: %v\\n", r) + } + }() + + panic("嵌套 panic 示例") + }() + + fmt.Println() +} + +// demonstrateDeferWithPanicRecover 演示 defer 与 panic/recover 的配合 +func demonstrateDeferWithPanicRecover() { + fmt.Println("3. Defer 与 Panic/Recover 的配合:") + + // defer 的执行顺序 + fmt.Printf(" defer 的执行顺序:\\n") + + func() { + defer fmt.Printf(" defer 1\\n") + defer fmt.Printf(" defer 2\\n") + defer func() { + if r := recover(); r != nil { + fmt.Printf(" recover: %v\\n", r) + } + }() + defer fmt.Printf(" defer 3\\n") + + fmt.Printf(" 正常执行\\n") + panic("测试 defer 顺序") + fmt.Printf(" 这行不会执行\\n") + }() + + // 多层 defer 和 recover + fmt.Printf(" 多层 defer 和 recover:\\n") + + func() { + defer func() { + fmt.Printf(" 外层 defer 开始\\n") + if r := recover(); r != nil { + fmt.Printf(" 外层 recover: %v\\n", r) + } + fmt.Printf(" 外层 defer 结束\\n") + }() + + defer func() { + fmt.Printf(" 内层 defer 开始\\n") + defer func() { + if r := recover(); r != nil { + fmt.Printf(" 内层 recover: %v\\n", r) + } + }() + fmt.Printf(" 内层 defer 结束\\n") + }() + + panic("多层 defer 测试") + }() + + // defer 中的资源清理 + fmt.Printf(" defer 中的资源清理:\\n") + + processWithCleanup := func() { + // 模拟资源分配 + resource := "重要资源" + fmt.Printf(" 分配资源: %s\\n", resource) + + defer func() { + // 资源清理 + fmt.Printf(" 清理资源: %s\\n", resource) + + // 捕获 panic + if r := recover(); r != nil { + fmt.Printf(" 处理过程中发生 panic: %v\\n", r) + fmt.Printf(" 资源已安全清理\\n") + } + }() + + // 模拟可能 panic 的操作 + if time.Now().UnixNano()%2 == 0 { + panic("随机 panic") + } + + fmt.Printf(" 正常处理完成\\n") + } + + // 执行多次以演示不同情况 + for i := 0; i < 3; i++ { + fmt.Printf(" 执行 %d:\\n", i+1) + processWithCleanup() + } + + fmt.Println() +} + +// demonstratePanicPropagation 演示 panic 的传播 +func demonstratePanicPropagation() { + fmt.Println("4. Panic 的传播:") + + // panic 的栈展开 + fmt.Printf(" panic 的栈展开:\\n") + + func() { + defer func() { + if r := recover(); r != nil { + fmt.Printf(" 最终捕获 panic: %v\\n", r) + + // 打印调用栈 + buf := make([]byte, 1024) + n := runtime.Stack(buf, false) + fmt.Printf(" 调用栈:\\n%s\\n", buf[:n]) + } + }() + + level1() + }() + + // panic 的中途拦截 + fmt.Printf(" panic 的中途拦截:\\n") + + func() { + defer func() { + if r := recover(); r != nil { + fmt.Printf(" 最外层捕获: %v\\n", r) + } + }() + + interceptedLevel1() + }() + + // panic 的重新抛出 + fmt.Printf(" panic 的重新抛出:\\n") + + func() { + defer func() { + if r := recover(); r != nil { + fmt.Printf(" 最终处理 panic: %v\\n", r) + } + }() + + rethrowLevel1() + }() + + fmt.Println() +} + +// demonstratePracticalUsage 演示 panic/recover 的实际应用 +func demonstratePracticalUsage() { + fmt.Println("5. Panic/Recover 的实际应用:") + + // Web 服务器中的 panic 恢复 + fmt.Printf(" Web 服务器中的 panic 恢复:\\n") + + requests := []string{ + "/api/users", + "/api/panic", + "/api/orders", + "/api/error", + } + + for _, path := range requests { + handleHTTPRequest(path) + } + + // 工作池中的 panic 处理 + fmt.Printf(" 工作池中的 panic 处理:\\n") + + jobs := []Job{ + {ID: 1, Data: "正常任务"}, + {ID: 2, Data: "panic任务"}, + {ID: 3, Data: "正常任务"}, + {ID: 4, Data: "error任务"}, + } + + for _, job := range jobs { + processJobSafely(job) + } + + // 数据解析中的 panic 处理 + fmt.Printf(" 数据解析中的 panic 处理:\\n") + + data := []string{ + "123", + "abc", + "456", + "", + "789", + } + + for _, item := range data { + result := parseIntSafely(item) + fmt.Printf(" 解析 '%s': %d\\n", item, result) + } + + // 递归函数中的 panic 处理 + fmt.Printf(" 递归函数中的 panic 处理:\\n") + + testValues := []int{5, -1, 10, 0} + for _, n := range testValues { + result := safeFactorial(n) + fmt.Printf(" %d! = %d\\n", n, result) + } + + fmt.Println() +} + +// demonstrateBestPractices 演示最佳实践 +func demonstrateBestPractices() { + fmt.Println("6. 最佳实践:") + + // 最佳实践原则 + fmt.Printf(" 最佳实践原则:\\n") + fmt.Printf(" 1. 优先使用错误返回值而不是 panic\\n") + fmt.Printf(" 2. 只在真正异常的情况下使用 panic\\n") + fmt.Printf(" 3. 在库代码中避免 panic,转换为错误\\n") + fmt.Printf(" 4. 在应用边界使用 recover 保护\\n") + fmt.Printf(" 5. 记录 panic 信息用于调试\\n") + + // 库函数的 panic 处理 + fmt.Printf(" 库函数的 panic 处理:\\n") + + // 不好的做法:库函数直接 panic + fmt.Printf(" 不好的做法示例:\\n") + result, err := callLibraryFunction("invalid") + if err != nil { + fmt.Printf(" 库函数错误: %v\\n", err) + } else { + fmt.Printf(" 库函数结果: %s\\n", result) + } + + // 好的做法:将 panic 转换为错误 + fmt.Printf(" 好的做法示例:\\n") + result, err = safeLibraryFunction("invalid") + if err != nil { + fmt.Printf(" 安全库函数错误: %v\\n", err) + } else { + fmt.Printf(" 安全库函数结果: %s\\n", result) + } + + // panic 信息的记录 + fmt.Printf(" panic 信息的记录:\\n") + + func() { + defer func() { + if r := recover(); r != nil { + logPanic(r) + } + }() + + panic("需要记录的 panic") + }() + + // 优雅的服务关闭 + fmt.Printf(" 优雅的服务关闭:\\n") + + server := &Server{name: "测试服务器"} + server.Start() + + // 模拟服务运行中的 panic + func() { + defer server.handlePanic() + panic("服务运行时错误") + }() + + server.Stop() + + fmt.Println() +} + +// demonstrateErrorVsPanic 演示错误处理 vs panic 的选择 +func demonstrateErrorVsPanic() { + fmt.Println("7. 错误处理 vs Panic 的选择:") + + // 使用错误的场景 + fmt.Printf(" 使用错误的场景:\\n") + fmt.Printf(" - 预期可能发生的错误\\n") + fmt.Printf(" - 用户输入错误\\n") + fmt.Printf(" - 网络或I/O错误\\n") + fmt.Printf(" - 业务逻辑错误\\n") + + // 使用 panic 的场景 + fmt.Printf(" 使用 panic 的场景:\\n") + fmt.Printf(" - 程序逻辑错误\\n") + fmt.Printf(" - 不可恢复的错误\\n") + fmt.Printf(" - 初始化失败\\n") + fmt.Printf(" - 断言失败\\n") + + // 对比示例 + fmt.Printf(" 对比示例:\\n") + + // 错误处理示例 + fmt.Printf(" 错误处理示例:\\n") + result, err := divide(10, 0) + if err != nil { + fmt.Printf(" 除法错误: %v\\n", err) + } else { + fmt.Printf(" 除法结果: %.2f\\n", result) + } + + // panic 示例 + fmt.Printf(" panic 示例:\\n") + func() { + defer func() { + if r := recover(); r != nil { + fmt.Printf(" 捕获 panic: %v\\n", r) + } + }() + + assertPositive(-5) + }() + + // 混合使用示例 + fmt.Printf(" 混合使用示例:\\n") + + calculator := &Calculator{} + + // 正常计算 + result, err = calculator.Calculate("10 + 5") + if err != nil { + fmt.Printf(" 计算错误: %v\\n", err) + } else { + fmt.Printf(" 计算结果: %.2f\\n", result) + } + + // 无效表达式 + result, err = calculator.Calculate("invalid") + if err != nil { + fmt.Printf(" 计算错误: %v\\n", err) + } else { + fmt.Printf(" 计算结果: %.2f\\n", result) + } + + // 内部 panic 被转换为错误 + result, err = calculator.Calculate("panic") + if err != nil { + fmt.Printf(" 计算错误: %v\\n", err) + } else { + fmt.Printf(" 计算结果: %.2f\\n", result) + } + + fmt.Println() +} + +// ========== 辅助函数和类型定义 ========== + +// safeFunction 安全执行函数 +func safeFunction(fn func() int) int { + defer func() { + if r := recover(); r != nil { + fmt.Printf(" 函数执行中发生 panic,已恢复: %v\\n", r) + } + }() + + return fn() +} + +// level1 第一层函数 +func level1() { + defer func() { + fmt.Printf(" level1 defer 执行\\n") + }() + + fmt.Printf(" 进入 level1\\n") + level2() + fmt.Printf(" level1 正常结束\\n") +} + +// level2 第二层函数 +func level2() { + defer func() { + fmt.Printf(" level2 defer 执行\\n") + }() + + fmt.Printf(" 进入 level2\\n") + level3() + fmt.Printf(" level2 正常结束\\n") +} + +// level3 第三层函数 +func level3() { + defer func() { + fmt.Printf(" level3 defer 执行\\n") + }() + + fmt.Printf(" 进入 level3\\n") + panic("level3 中的 panic") + fmt.Printf(" level3 正常结束\\n") +} + +// interceptedLevel1 中途拦截的第一层 +func interceptedLevel1() { + defer func() { + fmt.Printf(" interceptedLevel1 defer\\n") + }() + + fmt.Printf(" 进入 interceptedLevel1\\n") + interceptedLevel2() + fmt.Printf(" interceptedLevel1 正常结束\\n") +} + +// interceptedLevel2 中途拦截的第二层 +func interceptedLevel2() { + defer func() { + if r := recover(); r != nil { + fmt.Printf(" interceptedLevel2 拦截 panic: %v\\n", r) + // 不重新抛出,panic 在这里被处理 + } + fmt.Printf(" interceptedLevel2 defer\\n") + }() + + fmt.Printf(" 进入 interceptedLevel2\\n") + interceptedLevel3() + fmt.Printf(" interceptedLevel2 正常结束\\n") +} + +// interceptedLevel3 中途拦截的第三层 +func interceptedLevel3() { + defer func() { + fmt.Printf(" interceptedLevel3 defer\\n") + }() + + fmt.Printf(" 进入 interceptedLevel3\\n") + panic("interceptedLevel3 中的 panic") + fmt.Printf(" interceptedLevel3 正常结束\\n") +} + +// rethrowLevel1 重新抛出的第一层 +func rethrowLevel1() { + defer func() { + fmt.Printf(" rethrowLevel1 defer\\n") + }() + + fmt.Printf(" 进入 rethrowLevel1\\n") + rethrowLevel2() + fmt.Printf(" rethrowLevel1 正常结束\\n") +} + +// rethrowLevel2 重新抛出的第二层 +func rethrowLevel2() { + defer func() { + if r := recover(); r != nil { + fmt.Printf(" rethrowLevel2 捕获并重新抛出 panic: %v\\n", r) + panic(fmt.Sprintf("重新抛出: %v", r)) // 重新抛出 + } + fmt.Printf(" rethrowLevel2 defer\\n") + }() + + fmt.Printf(" 进入 rethrowLevel2\\n") + rethrowLevel3() + fmt.Printf(" rethrowLevel2 正常结束\\n") +} + +// rethrowLevel3 重新抛出的第三层 +func rethrowLevel3() { + defer func() { + fmt.Printf(" rethrowLevel3 defer\\n") + }() + + fmt.Printf(" 进入 rethrowLevel3\\n") + panic("rethrowLevel3 中的 panic") + fmt.Printf(" rethrowLevel3 正常结束\\n") +} + +// handleHTTPRequest 处理HTTP请求 +func handleHTTPRequest(path string) { + defer func() { + if r := recover(); r != nil { + fmt.Printf(" HTTP请求 %s 发生 panic,已恢复: %v\\n", path, r) + // 在实际应用中,这里会返回 500 错误 + } + }() + + fmt.Printf(" 处理请求: %s\\n", path) + + switch path { + case "/api/panic": + panic("模拟处理器 panic") + case "/api/error": + // 这里应该返回错误而不是 panic + fmt.Printf(" 请求处理出错\\n") + default: + fmt.Printf(" 请求处理成功\\n") + } +} + +// Job 任务结构 +type Job struct { + ID int + Data string +} + +// processJobSafely 安全处理任务 +func processJobSafely(job Job) { + defer func() { + if r := recover(); r != nil { + fmt.Printf(" 任务 %d 处理时发生 panic,已恢复: %v\\n", job.ID, r) + } + }() + + fmt.Printf(" 处理任务 %d: %s\\n", job.ID, job.Data) + + switch job.Data { + case "panic任务": + panic("任务处理中的 panic") + case "error任务": + fmt.Printf(" 任务处理出错\\n") + default: + fmt.Printf(" 任务处理成功\\n") + } +} + +// parseIntSafely 安全解析整数 +func parseIntSafely(s string) int { + defer func() { + if r := recover(); r != nil { + fmt.Printf(" 解析 '%s' 时发生 panic: %v\\n", s, r) + } + }() + + if s == "" { + panic("空字符串无法解析") + } + + result, err := strconv.Atoi(s) + if err != nil { + return 0 // 返回默认值 + } + + return result +} + +// safeFactorial 安全计算阶乘 +func safeFactorial(n int) int { + defer func() { + if r := recover(); r != nil { + fmt.Printf(" 计算 %d! 时发生 panic: %v\\n", n, r) + } + }() + + return factorial(n) +} + +// factorial 计算阶乘(可能 panic) +func factorial(n int) int { + if n < 0 { + panic("负数没有阶乘") + } + if n == 0 || n == 1 { + return 1 + } + return n * factorial(n-1) +} + +// callLibraryFunction 库函数(不好的做法) +func callLibraryFunction(input string) (string, error) { + // 这个函数直接 panic,不是好的做法 + if input == "invalid" { + panic("库函数中的 panic") + } + return "处理结果: " + input, nil +} + +// safeLibraryFunction 安全的库函数 +func safeLibraryFunction(input string) (result string, err error) { + defer func() { + if r := recover(); r != nil { + err = fmt.Errorf("库函数内部错误: %v", r) + } + }() + + // 调用可能 panic 的函数 + return callLibraryFunction(input) +} + +// logPanic 记录 panic 信息 +func logPanic(r interface{}) { + fmt.Printf(" [PANIC LOG] 时间: %s\\n", time.Now().Format("2006-01-02 15:04:05")) + fmt.Printf(" [PANIC LOG] 错误: %v\\n", r) + fmt.Printf(" [PANIC LOG] 类型: %T\\n", r) + + // 获取调用栈 + buf := make([]byte, 1024) + n := runtime.Stack(buf, false) + fmt.Printf(" [PANIC LOG] 调用栈:\\n%s\\n", buf[:n]) +} + +// Server 服务器结构 +type Server struct { + name string +} + +func (s *Server) Start() { + fmt.Printf(" 服务器 %s 启动\\n", s.name) +} + +func (s *Server) Stop() { + fmt.Printf(" 服务器 %s 停止\\n", s.name) +} + +func (s *Server) handlePanic() { + if r := recover(); r != nil { + fmt.Printf(" 服务器 %s 捕获 panic: %v\\n", s.name, r) + fmt.Printf(" 服务器继续运行\\n") + } +} + +// divide 除法运算 +func divide(a, b float64) (float64, error) { + if b == 0 { + return 0, fmt.Errorf("除数不能为零") + } + return a / b, nil +} + +// assertPositive 断言为正数 +func assertPositive(n int) { + if n <= 0 { + panic(fmt.Sprintf("断言失败: %d 不是正数", n)) + } + fmt.Printf(" 断言通过: %d 是正数\\n", n) +} + +// Calculator 计算器 +type Calculator struct{} + +func (c *Calculator) Calculate(expression string) (result float64, err error) { + defer func() { + if r := recover(); r != nil { + err = fmt.Errorf("计算表达式 '%s' 时发生内部错误: %v", expression, r) + } + }() + + switch expression { + case "10 + 5": + return 15, nil + case "invalid": + return 0, fmt.Errorf("无效的表达式: %s", expression) + case "panic": + panic("计算器内部 panic") + default: + return 0, fmt.Errorf("不支持的表达式: %s", expression) + } +} + +/* +运行这个程序: +go run 03-panic-recover.go + +学习要点: +1. panic 是运行时错误,会导致程序崩溃 +2. recover 只能在 defer 函数中使用来捕获 panic +3. defer 语句按照 LIFO 顺序执行 +4. panic 会沿着调用栈向上传播 +5. panic/recover 应该谨慎使用,优先使用错误处理 + +Panic 的特性: +1. 停止当前函数的正常执行 +2. 执行当前函数的所有 defer 语句 +3. 向上传播到调用函数 +4. 如果没有被 recover,程序会崩溃 +5. 可以携带任意类型的值 + +Recover 的特性: +1. 只能在 defer 函数中直接调用 +2. 返回 panic 的值,如果没有 panic 返回 nil +3. 只能捕获当前 goroutine 的 panic +4. 捕获后程序可以继续执行 +5. 可以根据 panic 值进行不同处理 + +常见的 Panic 场景: +1. 数组或切片越界访问 +2. 空指针解引用 +3. 类型断言失败(不安全断言) +4. 向已关闭的 channel 发送数据 +5. 除零操作(整数除法) + +使用场景: +1. Panic 适用场景: + - 程序逻辑错误 + - 不可恢复的错误 + - 初始化失败 + - 断言失败 + +2. Error 适用场景: + - 预期可能发生的错误 + - 用户输入错误 + - 网络或I/O错误 + - 业务逻辑错误 + +最佳实践: +1. 优先使用错误返回值而不是 panic +2. 只在真正异常的情况下使用 panic +3. 在库代码中避免 panic,转换为错误 +4. 在应用边界使用 recover 保护 +5. 记录 panic 信息用于调试 +6. 使用 defer 进行资源清理 + +注意事项: +1. recover 只能在 defer 中直接调用 +2. 不要忽略 recover 的返回值 +3. panic 会影响程序性能 +4. 过度使用 panic/recover 会使代码难以理解 +5. 在 goroutine 中的 panic 需要单独处理 + +实际应用: +1. Web 服务器的 panic 恢复中间件 +2. 工作池中的任务 panic 处理 +3. 数据解析中的异常处理 +4. 递归函数的栈溢出保护 +5. 库函数的 panic 转错误 + +性能考虑: +1. panic/recover 有一定的性能开销 +2. 不应该用于正常的控制流 +3. 频繁的 panic/recover 会影响性能 +4. 错误处理通常比 panic/recover 更高效 +5. 在性能敏感的代码中谨慎使用 +*/