我有一个Go程序,它将字符串写入文件。我有一个迭代 20000次的循环,并且在每次迭代中我将大约20-30个字符串写入文件。我只是想知道哪个是将其写入文件的最佳方式。
方法1:在代码的开头保持打开文件指针 为每个字符串写它。它使它成为20000 * 30的写操作。
方法2:使用bytes.Buffer Go并将所有内容存储在缓冲区中 在最后写它。在这种情况下,文件指针应该是 从代码的开头或代码的末尾打开。是否 这很重要吗?
我假设方法2应该更好。有人可以用一个理由证实这一点。 如何立即写作比定期写作更好。因为文件指针无论如何都会打开。
我使用的是f.WriteString(<string>)
,buffer.WriteString(<some string>)
缓冲区的类型为bytes.Buffer
,而f
的文件指针是打开的。
答案 0 :(得分:7)
bufio包。在进行系统调用之前,不要为每个Write调用bufio.Writer
进行系统调用,而是在内部存储器中缓冲到固定数量的字节。在系统调用之后,内部缓冲区被重用于下一部分数据
与您的第二种方法相比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)
}
答案 1 :(得分:3)
在文件中写入时需要花费时间的操作是系统调用和磁盘I / O.文件指针打开的事实并不会让您付出任何代价。天真地说,我们可以说第二种方法是最好的。
现在,正如您所知,您的操作系统并不直接写入文件,它使用内部内存缓存来处理写入的文件,并在以后执行真正的I / O.我不知道具体细节,一般来说我不需要。
我建议的是一个中间解决方案:为每个循环迭代做一个缓冲,然后写这个N次。这样可以减少系统调用和(可能)磁盘写入的大部分,但不会消耗过多的缓冲区内存(依赖于字符串的大小,我需要考虑到这一点)。< / p>
我建议为最佳解决方案进行基准测试,但由于系统进行了缓存,基准磁盘I / O是一个真正的噩梦。
答案 2 :(得分:1)
Syscalls并不便宜,所以第二种方法更好。
您可以使用lmbench中的lat_syscall工具来衡量调用单write
所需的时间:
$ ./lat_syscall write
Simple write: 0.1522 microseconds
因此,在我的系统上,每个字符串调用write
需要大约20000 *0.15μs= 3ms的额外时间。