diff --git a/Golang/Golang Document.md b/Golang/Golang Document.md index be5ba21..f265db1 100644 --- a/Golang/Golang Document.md +++ b/Golang/Golang Document.md @@ -72,6 +72,8 @@ - [time.Duration](#timeduration) - [Bufio](#bufio) - [Buffered Reader](#buffered-reader) + - [Buffered Writer](#buffered-writer) + - [修改缓冲区大小](#修改缓冲区大小) - [syntax](#syntax) - [iota](#iota) @@ -1568,6 +1570,151 @@ ok git.kazusa.red/asahi/bufio 9.254s 可知,带缓冲场景下10M文件每次读取花费`0.03209 ns`,而不带缓冲按字节读取时每次读取花费`8.93s`。 +### Buffered Writer +类似于`bufio.NewReader`方法,可以通过`bufio.NewWriter`方法来创建一个buffered writer,该方法接受`io.Writer`作为参数。 + +通常,可以将`os.File, stirngs.Builder, bytes.Buffer`作为参数传入。 + +在写入大小为50M的文件时,其性能测试如下. + +带缓冲和不带缓冲的代码实现 +```go +func WriteToFileWithoutBuf(filename string, n uint32, generate func () []byte) (err error) { + file, err := os.OpenFile(filename, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0740) + if err != nil { + return + } + defer file.Close() + for i := 0; uint32(i) < n; i++ { + _, err = file.Write(generate()) + if err != nil { + break + } + } + return +} + +func WriteToFileWithBuf(filename string, n uint32, generate func () []byte) (err error) { + file, err := os.OpenFile(filename, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0740) + if err != nil { + return + } + defer file.Close() + w := bufio.NewWriter(file) + for i := 0; uint32(i) < n; i++ { + _, err = w.Write(generate()) + if err != nil { + break + } + } + defer func(w *bufio.Writer) { + err := w.Flush() + if err != nil { + + } + }(w) + return +} +``` +benchmark代码如下所示: +```go +func BenchmarkWriteToFileWithBuf(b *testing.B) { + if err := WriteToFileWithBuf(WriteFileName, 1024*1024*10, generateCharsSlice); err != nil { + panic(any(err)) + } +} + +func BenchmarkWriteToFileWithoutBuf(b *testing.B) { + if err := WriteToFileWithoutBuf(WriteFileName, 1024*1024*10, generateCharsSlice); err != nil { + panic(any(err)) + } +} + +func generateCharsSlice() []byte { + return []byte("asahi") +} +``` +执行benmark命令进行测试: +```bash +go test -bench=BenchmarkWriteToFile.* +``` +测试结果如下所示: +```go +goos: windows +goarch: amd64 +pkg: git.kazusa.red/asahi/bufio +cpu: AMD Ryzen 9 7950X 16-Core Processor +BenchmarkWriteToFileWithBuf-32 1000000000 0.1407 ns/op +BenchmarkWriteToFileWithoutBuf-32 1 13251963400 ns/op +PASS +ok git.kazusa.red/asahi/bufio 14.945s +``` +易知当使用带缓冲版本时,50M大小的文件写入事件为`0.1407ns`,而当使用不带缓冲的操作时,写入时间则需要花费`13s` + +### 修改缓冲区大小 +默认情况下,通过`NewReader`, `NewWriter`方法生成的buffered reader或writer,其缓冲区大小默认为`4096`字节。 + +当想要修改缓冲区大小是,可以使用`NewReaderSize`方法,该方法额外接受一个定义缓冲区大小的参数。 + +代码如下 +```go +func WriteToFileWithBufSize(filename string, n uint32, bufSize int, generate func() []byte) (err error) { + file, err := os.OpenFile(filename, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0740) + if err != nil { + return + } + defer file.Close() + w := bufio.NewWriterSize(file, bufSize) + for i := 0; uint32(i) < n; i++ { + _, err = w.Write(generate()) + if err != nil { + break + } + } + defer func(w *bufio.Writer) { + err := w.Flush() + if err != nil { + + } + }(w) + return +} +``` + +测试代码如下: +```go +func BenchmarkWriteToFileWith4KBuf(b *testing.B) { + if err := WriteToFileWithBufSize(WriteFileName, 1024*1024*10, 4096, generateCharsSlice); err != nil { + panic(any(err)) + } +} + +func BenchmarkWriteToFileWith128BytesBuf(b *testing.B) { + if err := WriteToFileWithBufSize(WriteFileName, 1024*1024*10, 128, generateCharsSlice); err != nil { + panic(any(err)) + } +} +``` + +benchmark命令如下: +```bash +go test -bench="BenchmarkWriteToFileWith(4K|128Bytes)Buf" +``` + +benchmark结果如下: +```go +goos: windows +goarch: amd64 +pkg: git.kazusa.red/asahi/bufio +cpu: AMD Ryzen 9 7950X 16-Core Processor +BenchmarkWriteToFileWith4KBuf-32 1000000000 0.1383 ns/op +BenchmarkWriteToFileWith128BytesBuf-32 1000000000 0.6549 ns/op +PASS +ok git.kazusa.red/asahi/bufio 26.042s +``` + +易知,当读写50M文件时,缓冲区大小为4096时每次写操作耗时`0.1383ns`,而将缓冲区修改为128大小后,每次写操作耗时增加到`0.65ns` +