我有一个Go程序,它将字符串写入文件。我有一个迭代20000次的循环,在每次迭代中我将大约20-30个字符串写入文件。我只是想知道哪个是将其写入文件的最佳方式。
我假设方法2应该更好。有人可以用一个理由证实这一点。如何立即写作比定期写作更好。因为文件指针无论如何都会打开。我使用f.WriteString(<string>)
和buffer.WriteString(<some string>)
缓冲区是bytes.Buffer
类型和f
是文件指针打开。
bufio包是为这种任务创建的。在进行系统调用之前,bufio.Writer
不会为每个Write调用进行系统调用,而是在内部存储器中缓冲固定数量的字节。在系统调用之后,内部缓冲区将重用于下一部分数据
与您的第二种方法bufio.Writer
相比
N/S
而不是1
)S
字节而不是N
字节)其中S
- 是缓冲区大小(可以通过bufio.NewWriterSize
指定),N
- 需要写入的数据的总大小。
用法示例(https://play.golang.org/p/AvBE1d6wpT):
f, err := os.Create("file.txt")
if err != nil {
log.Fatal(err)
}
defer f.Close()
w := bufio.NewWriter(f)
fmt.Fprint(w, "Hello, ")
fmt.Fprint(w, "world!")
err = w.Flush() // Don't forget to flush!
if err != nil {
log.Fatal(err)
}
写入文件时花费时间的操作是系统调用和磁盘I / O.文件指针打开的事实不会花费任何成本。天真地说,我们可以说第二种方法是最好的。
现在,正如您所知,您的操作系统不直接写入文件,它使用内部内存缓存来处理写入的文件,并在以后执行真正的I / O.我不知道具体细节,一般来说我不需要。
我建议的是一个中间解决方案:为每个循环迭代做一个缓冲,然后写这个N次。这样可以减少系统调用和(可能)磁盘写入的大部分,但不会消耗过多的缓冲区内存(依赖于字符串的大小,我应该考虑到这一点)。
我建议为最佳解决方案进行基准测试,但由于系统进行了缓存,基准磁盘I / O是一个真正的噩梦。
Syscalls并不便宜,所以第二种方法更好。
您可以使用lmbench中的lat_syscall工具来测量调用单个write
所需的时间:
$ ./lat_syscall write
Simple write: 0.1522 microseconds
因此,在我的系统上,每个字符串调用write
需要大约20000 *0.15μs= 3ms的额外时间。