package main
import (
"context"
"fmt"
"math/rand"
"sync"
"time"
)
// 模拟的数据结构
type UserInfo struct {
ID int
Name string
Age int
}
type OrderHistory struct {
Orders []string
Total float64
}
type Recommendations struct {
Items []string
}
// 模拟的数据库/API客户端
type APIClient struct{}
// 1. 获取用户信息(模拟数据库查询)
func (c *APIClient) GetUserInfo(ctx context.Context, userID int) (*UserInfo, error) {
select {
case <-ctx.Done():
fmt.Println("GetUserInfo: 请求被取消")
return nil, ctx.Err()
case <-time.After(time.Duration(rand.Intn(2000)) * time.Millisecond): // 模拟0-2秒延迟
return &UserInfo{ID: userID, Name: fmt.Sprintf("用户%d", userID), Age: 25}, nil
}
}
// 2. 获取订单历史(模拟外部API调用)
func (c *APIClient) GetOrderHistory(ctx context.Context, userID int) (*OrderHistory, error) {
// 模拟10%的失败率
if rand.Intn(10) == 0 {
return nil, fmt.Errorf("订单服务暂时不可用")
}
select {
case <-ctx.Done():
fmt.Println("GetOrderHistory: 请求被取消")
return nil, ctx.Err()
case <-time.After(time.Duration(800+rand.Intn(1200)) * time.Millisecond): // 0.8-2秒延迟
return &OrderHistory{
Orders: []string{"订单A", "订单B", "订单C"},
Total: 299.99,
}, nil
}
}
// 3. 获取推荐内容(模拟缓存查询)
func (c *APIClient) GetRecommendations(ctx context.Context, userID int) (*Recommendations, error) {
select {
case <-ctx.Done():
fmt.Println("GetRecommendations: 请求被取消")
return nil, ctx.Err()
case <-time.After(time.Duration(rand.Intn(1000)) * time.Millisecond): // 0-1秒延迟
return &Recommendations{
Items: []string{"推荐商品A", "推荐商品B", "推荐商品C"},
}, nil
}
}
// 聚合器:并发获取所有数据
type Aggregator struct {
client *APIClient
}
// Result 包装每个请求的结果
type Result struct {
DataType string // 数据类型
Data interface{} // 实际数据
Err error // 错误信息
}
// AggregateUserData 并发聚合用户数据
func (a *Aggregator) AggregateUserData(ctx context.Context, userID int) map[string]interface{} {
// 创建带有超时的上下文(3秒后超时)
ctx, cancel := context.WithTimeout(ctx, 3*time.Second)
defer cancel() // 确保释放资源
// 创建带缓冲的channel,避免goroutine泄漏
resultChan := make(chan Result, 3)
var wg sync.WaitGroup
// 1. 启动获取用户信息的goroutine
wg.Add(1)
go func() {
defer wg.Done()
userInfo, err := a.client.GetUserInfo(ctx, userID)
resultChan <- Result{"user_info", userInfo, err}
}()
// 2. 启动获取订单历史的goroutine
wg.Add(1)
go func() {
defer wg.Done()
orders, err := a.client.GetOrderHistory(ctx, userID)
resultChan <- Result{"order_history", orders, err}
}()
// 3. 启动获取推荐内容的goroutine
wg.Add(1)
go func() {
defer wg.Done()
recommendations, err := a.client.GetRecommendations(ctx, userID)
resultChan <- Result{"recommendations", recommendations, err}
}()
// 独立的goroutine等待所有任务完成并关闭channel
go func() {
wg.Wait()
close(resultChan)
}()
// 主goroutine收集结果
results := make(map[string]interface{})
// 关键部分:使用select监听多个channel
for {
select {
case <-ctx.Done():
// 上下文被取消或超时
fmt.Printf("\n聚合请求超时或被取消: %v\n", ctx.Err())
// 尝试收集已经完成的结果
fmt.Println("已收集到的部分结果:")
for k, v := range results {
fmt.Printf(" %s: %v\n", k, v)
}
// 添加超时标记
results["timeout"] = true
return results
case result, ok := <-resultChan:
if !ok {
// channel已关闭,所有结果收集完成
fmt.Println("\n所有请求完成!")
return results
}
// 处理单个结果
if result.Err != nil {
fmt.Printf("获取 %s 失败: %v\n", result.DataType, result.Err)
results[result.DataType+"_error"] = result.Err.Error()
} else {
fmt.Printf("成功获取 %s\n", result.DataType)
results[result.DataType] = result.Data
}
}
}
}
func main() {
fmt.Println("=== Go并发编程示例:API数据聚合 ===")
client := &APIClient{}
aggregator := &Aggregator{client: client}
// 测试1: 正常情况
fmt.Println("测试1: 正常请求(3秒超时)")
fmt.Println("------------------------")
start := time.Now()
results := aggregator.AggregateUserData(context.Background(), 123)
elapsed := time.Since(start)
fmt.Printf("\n总耗时: %v\n", elapsed)
fmt.Printf("收集到的数据类型数量: %d\n\n", len(results))
// 显示部分结果
if userInfo, ok := results["user_info"]; ok {
fmt.Printf("用户信息: %+v\n", userInfo)
}
// 测试2: 模拟手动取消
fmt.Println("\n\n测试2: 手动取消请求")
fmt.Println("-------------------")
ctx, cancel := context.WithCancel(context.Background())
// 启动一个goroutine在500ms后取消请求
go func() {
time.Sleep(500 * time.Millisecond)
fmt.Println("\n发送取消信号...")
cancel()
}()
start = time.Now()
results = aggregator.AggregateUserData(ctx, 456)
fmt.Println("results", results)
elapsed = time.Since(start)
fmt.Printf("\n请求在 %v 后被取消\n", elapsed)
// 测试3: 模拟外部中断
fmt.Println("\n\n测试3: 模拟外部中断处理")
fmt.Println("-----------------------")
interruptChan := make(chan struct{}, 1)
// 创建一个可以响应中断的上下文
ctx, cancel = context.WithCancel(context.Background())
defer cancel()
// 模拟外部中断(如用户按Ctrl+C)
go func() {
time.Sleep(700 * time.Millisecond)
fmt.Println("\n[系统] 收到中断信号")
interruptChan <- struct{}{}
}()
// 启动聚合请求
go func() {
results := aggregator.AggregateUserData(ctx, 789)
fmt.Printf("\n中断测试结果: %d个数据项\n", len(results))
}()
// 监听中断信号
select {
case <-interruptChan:
fmt.Println("[系统] 正在取消所有请求...")
cancel() // 取消上下文
time.Sleep(100 * time.Millisecond) // 给goroutine一些时间响应
case <-time.After(2 * time.Second):
fmt.Println("[系统] 未收到中断信号")
}
time.Sleep(1 * time.Second) // 等待所有输出完成
fmt.Println("\n=== 示例结束 ===")
}