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())
    }
}

 

posted @ 2025-05-10 17:49  zhjh256  阅读(3)  评论(0)    收藏  举报