写操作费用[Go lang]
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了写操作费用[Go lang]相关的知识,希望对你有一定的参考价值。
我有一个Go程序,它将字符串写入文件。我有一个迭代20000次的循环,在每次迭代中我将大约20-30个字符串写入文件。我只是想知道哪个是将其写入文件的最佳方式。
- 方法1:在代码的开头保持打开文件指针,并为每个字符串写入。它使它成为20000 * 30的写操作。
- 方法2:使用bytes.Buffer Go并将所有内容存储在缓冲区中并在末尾写入。在这种情况下,文件指针应该从代码的开头或代码的末尾打开。有关系吗?
我假设方法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的额外时间。
以上是关于写操作费用[Go lang]的主要内容,如果未能解决你的问题,请参考以下文章
[Go] 通过 17 个简短代码片段,切底弄懂 channel 基础
java.lang.IllegalStateException:onSaveInstanceState On Activity Backpress 后无法执行此操作(不使用任何片段)
java.lang.IllegalStateException:片段未附加到活动
在 Android 片段中获取 Java.Lang.NullPointerException
java.lang.NullPointerException: Attempt to invoke virtual method ‘int android.database.sqlite异常(代码片段