golang父协程实时获取子协程的状态
package main import ( "context" "flag" "fmt" "log" "os" "os/signal" "syscall" "time" ) // 配置结构体,用于存储命令行参数和配置信息 type Config struct { Count int // 生成的斐波那契数列长度 Timeout time.Duration // 超时时间 LogLevel string // 日志级别 OutputDir string // 输出目录 } // 加载配置,从命令行参数获取 func loadConfig() Config { var cfg Config flag.IntVar(&cfg.Count, "n", 10, "生成的斐波那契数列长度") flag.DurationVar(&cfg.Timeout, "timeout", 5*time.Second, "超时时间") flag.StringVar(&cfg.LogLevel, "loglevel", "info", "日志级别 (debug, info, warn, error)") flag.StringVar(&cfg.OutputDir, "output", "./output", "输出目录") flag.Parse() return cfg } // 初始化日志记录器 func initLogger(level string) { // 设置日志格式 log.SetFlags(log.Ldate | log.Ltime | log.Lmicroseconds | log.Lshortfile) // 根据日志级别设置 switch level { case "debug": // 可以实现更详细的日志输出 case "info": // 默认设置 case "warn": // 可以过滤 info 级别的日志 case "error": // 可以只输出 error 级别的日志 default: log.Printf("未知日志级别: %s,使用默认设置\n", level) } } // 创建输出目录 func createOutputDir(dir string) error { if _, err := os.Stat(dir); os.IsNotExist(err) { if err := os.MkdirAll(dir, 0755); err != nil { return fmt.Errorf("创建输出目录失败: %v", err) } log.Printf("创建输出目录: %s\n", dir) } return nil } // 斐波那契数列生成器 func fibonacci(ctx context.Context, n int, c chan<- int) error { if n <= 0 { return fmt.Errorf("斐波那契数列长度必须大于0,实际为: %d", n) } x, y := 0, 1 for i := 0; i < n; i++ { select { case <-ctx.Done(): return ctx.Err() case c <- x: // 本身不会返回值,它只是一个发送操作 x, y = y, x+y log.Printf("生成斐波那契数: %d (第%d个)\n", x, i+1) } } return nil } // 将结果写入文件 func writeToFile(dir string, numbers []int) error { filePath := fmt.Sprintf("%s/fibonacci_%d.txt", dir, time.Now().Unix()) file, err := os.Create(filePath) if err != nil { return fmt.Errorf("创建文件失败: %v", err) } defer file.Close() for _, num := range numbers { if _, err := file.WriteString(fmt.Sprintf("%d\n", num)); err != nil { return fmt.Errorf("写入文件失败: %v", err) } } log.Printf("结果已写入文件: %s\n", filePath) return nil } func main() { // 加载配置 cfg := loadConfig() log.Printf("配置加载完成: %+v\n", cfg) // 初始化日志 initLogger(cfg.LogLevel) // 创建输出目录 if err := createOutputDir(cfg.OutputDir); err != nil { log.Fatalf("初始化失败: %v", err) } // 创建带超时的上下文 ctx, cancel := context.WithTimeout(context.Background(), cfg.Timeout) defer cancel() // 创建通道和结果切片 c := make(chan int) var results []int // 启动生成器 goroutine go func() { if err := fibonacci(ctx, cfg.Count, c); err != nil { log.Printf("斐波那契生成器错误: %v\n", err) cancel() // 取消上下文 } close(c) // 确保通道最终被关闭 }() // 处理系统信号,优雅退出 sigCh := make(chan os.Signal, 1) signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM) // 接收结果并处理超时和中断 done := make(chan struct{}) go func() { for num := range c { results = append(results, num) fmt.Println(num) } done <- struct{}{} }() // 等待完成或超时 select { case <-done: log.Printf("成功生成 %d 个斐波那契数\n", len(results)) if err := writeToFile(cfg.OutputDir, results); err != nil { log.Printf("写入文件失败: %v\n", err) } case <-sigCh: log.Println("接收到中断信号,正在优雅退出...") cancel() // 等待 goroutine 完成 <-done log.Println("已成功清理资源") case <-ctx.Done(): log.Printf("操作超时: %v\n", ctx.Err()) } }