400行 代码 mergdown 工具简析

之前用这工具重构了早期的 ngroke,重构后的项目为 tikrok,用来反向代理,同样免费使用。现在总结一下这个工具的实现吧。
https://gitee.com/Talbot3/Mergdown

核心数据流程图

[命令行参数] 
→ 参数解析 
→ 目录遍历 → 路径过滤(类型/正则/排除) 
→ 任务队列 → 并发处理器 
→ 有序结果收集 → 文件流式写入

关键数据流分析

  1. 输入阶段
参数结构体{
  TargetDir    string   // 目标目录路径
  OutputPath   string   // 输出文件路径
  MergeTypes   []string // 文件类型过滤
  RegexPattern string   // 路径匹配正则
  ExcludeDirs  []string // 排除目录模式
}
  1. 目录遍历阶段
文件系统树 → WalkDir遍历 → 生成绝对路径列表
           ↓
路径转换 → 相对路径计算 → 过滤检查(三步验证):
                       1. 文件类型扩展名检查(MergeTypes)
                       2. 正则路径匹配(RegexPattern)
                       3. 排除目录匹配(ExcludeDirs)
           ↓
通过检查 → 生成有序任务队列(带序号索引)
  1. 并发处理阶段
任务队列 → 工作池(NumCPU数量) → 文件处理管道{
                                     ↓
                                     打开文件 → 二进制检测 → 内容处理:
                                                          ├─ 文本文件 → 流式读取(4KB块)
                                                          └─ 二进制 → 生成占位文本
                                     ↓
                                     Markdown片段生成(带原始序号)
                                   }
           ↓
结果通道(保序缓冲队列)
  1. 输出阶段
结果收集器 → 顺序重组 → 缓冲写入(64KB块) → 最终输出文件
                     ↓
错误处理 → 快速失败(首个错误终止流程)

关键数据结构

  1. 任务结构体
type task struct {
    index int32    // 全局自增序号(atomic控制)
    path  string   // 文件绝对路径
}
  1. 结果结构体
type result struct {
    index   int32      // 对应任务序号
    content chan []byte // 流式内容管道(避免大文件内存问题)
    err     error       // 错误信息
}

流量特征分析

  1. 内存控制机制
  • 滑动窗口写入:每个文件的处理结果通过channel分块传输
  • 双缓冲策略:收集器使用:
    • 内存缓存:64KB缓冲写
    • 磁盘缓冲:os.File的自动页缓存
  1. 并发控制参数
最大并行文件数 = min(runtime.NumCPU(), maxOpenFiles)
默认值:100(防止文件描述符耗尽)

异常流处理

  1. 错误传播路径
文件读取错误 → 结果通道 → 收集器 → 主协程终止
参数校验错误 → 直接退出
系统调用错误 → 日志记录+跳过文件
  1. 恢复机制
defer func() {
    if r := recover(); r != nil {
        log.Printf("Critical error: %v", r)
        os.Exit(1)
    }
}()

性能优化点

  1. 零拷贝优化
文件读取 → 块复制 → 直接写入channel(避免多次内存分配)
  1. 路径缓存重用
相对路径计算 → 每个文件仅计算1次 → 用于:
               - 正则匹配
               - 排除检查
               - Markdown标题生成
  1. 智能预读策略
// 二进制检测时预读512字节
header := make([]byte, headerReadLen)
n, _ := file.Read(header)
file.Seek(0, io.SeekStart) // 重置读指针

典型数据流示例

输入场景

./mergetool -mergtype go -exclude "testdata" -regex ".*service.*" ~/project

数据流轨迹

  1. 遍历~/project目录下所有文件
  2. 过滤非.go扩展名文件
  3. 排除路径包含testdata的目录
  4. 匹配路径包含service关键字
  5. 生成合并文档:project.md

内存变化曲线

初始内存:2MB(基础运行时)
处理峰值:约32MB(100个文件并发处理时)
稳定状态:约8MB(流式写入保持稳定)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值