文件生成、拷贝减少内存、CPU使用率办法
核心技术解析
1.零拷贝分片传输
内存映射 (mmap):将源文件直接映射到虚拟内存,分片操作 mapped[offset:end]仅生成内存视图,无数据复制。
直接写入:通过 destFile.Write()将分片数据直接写入目标文件,避免用户态缓冲区的额外拷贝
2.资源安全管理
defer链式释放:确保文件描述符和内存映射资源在任何情况下(包括错误)都会被释放
同步刷盘:destFile.Sync()强制内核缓存刷入磁盘,防止系统崩溃导致数据丢失(牺牲部分性能换取可靠性)
3.大文件友好设计
流式分片处理:按固定大小(4MB)逐片写入,支持 TB 级文件 而不会内存溢出
物理内存按需加载:操作系统通过缺页中断动态加载文件分片,减少瞬时内存压力
package main
import (
"fmt"
"github.com/edsrzf/mmap-go"
"log"
"os"
)
const chunkSize = 4 * 1024 * 1024 // 4MB分片
func main() {
if len(os.Args) < 2 {
log.Fatal("Usage: ./zero-copy-save <filename>")
}
filename := os.Args[1]
destFile := fmt.Sprintf("/tmp/%v", filename)
if err := saveFile(filename, destFile); err != nil {
log.Fatalf("Error: %v", err)
}
}
// 零拷贝分片保存到目标文件
func saveFile(inputFile, outputFile string) error {
// 1. 打开源文件(只读)
srcFile, err := os.Open(inputFile)
if err != nil {
return fmt.Errorf("open source file failed: %w", err)
}
defer srcFile.Close()
// 2. 内存映射源文件(零拷贝)
mapped, err := mmap.Map(srcFile, mmap.RDONLY, 0)
if err != nil {
return fmt.Errorf("mmap failed: %w", err)
}
defer mapped.Unmap()
// 3. 创建目标文件(覆盖写入)
destFile, err := os.Create(outputFile)
if err != nil {
return fmt.Errorf("create output file failed: %w", err)
}
defer destFile.Close()
// 4. 分片写入目标文件
for offset := 0; offset < len(mapped); {
end := offset + chunkSize
if end > len(mapped) {
end = len(mapped)
}
chunk := mapped[offset:end] // 直接引用内存分片
// 5. 零拷贝写入目标文件
if _, err := destFile.Write(chunk); err != nil {
return fmt.Errorf("write chunk failed: %w", err)
}
// 6. 可选:同步数据到磁盘(确保持久化)
if err := destFile.Sync(); err != nil {
log.Printf("Warning: sync failed (%v)", err)
}
log.Printf("Wrote chunk [offset=%d, size=%d]", offset, len(chunk))
offset = end
}
log.Printf("Saved %d bytes → %s", len(mapped), outputFile)
return nil
}