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