Golang中io.Copy与内存读取的性能对比
Golang中io.Copy与内存读取的性能对比
我想了解将文件读入内存与使用 io.Copy 写入目标之间有什么区别。这里有一个例子可以更清楚地说明:
- 将文件读入内存
file, err := os.Open(path)
if err != nil { return }
fileContents, err := ioutil.ReadAll(file)
if err != nil { return }
fi, err := file.Stat()
if err != nil { return }
file.Close()
body := &bytes.Buffer{}
writer := multipart.NewWriter(body)
part, err := writer.CreateFormFile(paramName, fi.Name())
if err != nil { return }
part.Write(fileContents)
writer.Close()
- 使用 io.Copy
file, err := os.Open(path)
if err != nil {
return
}
defer file.Close()
fi, err := file.Stat()
if err != nil {
return
}
body := &bytes.Buffer{}
writer := multipart.NewWriter(body)
part, err := writer.CreateFormFile(paramName, fi.Name())
if err != nil {
return
}
io.Copy(part, file)
我有点觉得,即使复制方法是直接写入到 part writer,这个变量仍然是在内存中 🤷 所以我看不出区别。🤔 🤔
更多关于Golang中io.Copy与内存读取的性能对比的实战教程也可以访问 https://www.itying.com/category-94-b0.html
两种方法做的事情基本相同,它们都使用了缓冲区。请查看以下源代码:
ioutil.ReadAll: https://cs.opensource.google/go/go/+/master:src/io/ioutil/ioutil.go;drc=3d913a926675d8d6fcdc3cfaefd3136dfeba06e1;l=26
更多关于Golang中io.Copy与内存读取的性能对比的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
io.Copy 与完全读入内存的主要区别在于内存使用模式和性能特征。以下是关键对比:
内存使用差异
完全读入内存方案:
fileContents, err := ioutil.ReadAll(file) // 一次性分配整个文件大小的内存
// 此时内存中同时存在:
// 1. fileContents 的完整副本
// 2. body.Buffer 中的另一个完整副本(通过 part.Write)
内存峰值 ≈ 文件大小 × 2
io.Copy 方案:
io.Copy(part, file) // 使用固定大小的缓冲区进行流式复制
内存峰值 ≈ 缓冲区大小(默认32KB)
性能基准测试示例
package main
import (
"bytes"
"io"
"mime/multipart"
"os"
"testing"
)
func BenchmarkReadAll(b *testing.B) {
for i := 0; i < b.N; i++ {
file, _ := os.Open("test.dat")
content, _ := io.ReadAll(file)
file.Close()
body := &bytes.Buffer{}
writer := multipart.NewWriter(body)
part, _ := writer.CreateFormFile("file", "test.dat")
part.Write(content)
writer.Close()
}
}
func BenchmarkIOCopy(b *testing.B) {
for i := 0; i < b.N; i++ {
file, _ := os.Open("test.dat")
defer file.Close()
body := &bytes.Buffer{}
writer := multipart.NewWriter(body)
part, _ := writer.CreateFormFile("file", "test.dat")
io.Copy(part, file)
writer.Close()
}
}
关键区别
- 内存效率:
io.Copy使用固定缓冲区(默认32KB)流式传输数据,避免一次性加载大文件 - 大文件处理:对于超过可用内存的文件,
ioutil.ReadAll会直接失败(panic: runtime error) - GC压力:
ReadAll创建的大对象给垃圾回收带来更大压力
实际影响示例
处理1GB文件时:
// 方案1:可能因内存不足而崩溃
content, _ := io.ReadAll(file) // 尝试分配1GB连续内存
// 方案2:稳定运行
io.Copy(part, file) // 仅使用32KB缓冲区
特殊情况
当需要多次访问数据时,完全读入内存可能更合适:
// 需要多次处理同一数据
content, _ := io.ReadAll(file)
process1(content)
process2(content) // 避免重复I/O
但在你的multipart表单示例中,数据只写入一次,io.Copy 是更优选择。它减少了内存分配次数,避免了不必要的完整拷贝,特别是在处理大文件时优势明显。

