编写运营成本[Go lang]

时间:2016-01-06 08:18:49

标签: performance go io

我有一个Go程序,它将字符串写入文件。我有一个迭代 20000次的循环,并且在每次迭代中我将大约20-30个字符串写入文件。我只是想知道哪个是将其写入文件的最佳方式。

  • 方法1:在代码的开头保持打开文件指针 为每个字符串写它。它使它成为20000 * 30的写操作。

  • 方法2:使用bytes.Buffer Go并将所有内容存储在缓冲区中 在最后写它。在这种情况下,文件指针应该是 从代码的开头或代码的末尾打开。是否 这很重要吗?

我假设方法2应该更好。有人可以用一个理由证实这一点。 如何立即写作比定期写作更好。因为文件指针无论如何都会打开。 我使用的是f.WriteString(<string>)buffer.WriteString(<some string>)缓冲区的类型为bytes.Buffer,而f的文件指针是打开的。

3 个答案:

答案 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的额外时间。