使用 bufio.NewScanner 逐行读取文件时的性能问题

我正在学习如何在 Go 中有效地读取非常大的文件。我已经尝试过bufio.NewScanner并bufio.NewReader使用ReadString('\n'). 在这两个选项中,NewScanner似乎始终更快(2:1)。


因为NewScanner我发现逐行读取文件比运行 unix cat 命令读取文件需要更多时间。


我测量了运行这段代码需要多长时间:


package main


import (

    "bufio"

    "fmt"

    "os"

)


func main() {


     file, _ := os.Open("test")

     scanner := bufio.NewScanner(file)

     for scanner.Scan() {

        fmt.Println(scanner.Text())

     }


}

当您与常规 unixcat输出进行比较时,我得到以下结果:


$ time ./parser3 > /dev/null

       19.13 real        13.81 user         5.94 sys

$ time cat test > /dev/null

        0.83 real         0.08 user         0.74 sys

几次执行之间的时间差是一致的。


我知道扫描'\n'会增加开销,而不是像 cat 那样将数据从输入复制到输出。


但是看到和这段代码片段之间的区别,cat我问自己这是否是在 Go 中逐行读取文件的最有效方法。


慕森王
浏览 415回答 2
2回答

30秒到达战场

根据 MuffinTop 的评论,这是提高速度的代码片段。性能损失与 Scanner 的使用无关,而是与以下事实有关:不在输出中使用缓冲使用scanner.Text()-which 分配一个字符串 - 而不是scanner.Bytes()添加输出缓冲的性能:package mainimport (    "bufio"    "fmt"    "os")func main() {     file, _ := os.Open("test")     w := bufio.NewWriter(os.Stdout)      scanner := bufio.NewScanner(file)     for scanner.Scan() {        fmt.Fprintln(w, scanner.Text())     }}上述解决方案使用输出缓冲,耗时 6.6 秒,而原来的 19.1 秒添加输出缓冲和使用.Bytes()而不是.Text()输出的性能:package mainimport (    "bufio"    "fmt"    "os")func main() {     file, _ := os.Open("test")     w := bufio.NewWriter(os.Stdout)      scanner := bufio.NewScanner(file)     for scanner.Scan() {        w.Write(scanner.Bytes()); w.WriteByte('\n')     }}上述解决方案使用输出缓冲并从扫描仪输出字节,并且需要 2.2 秒,而原来的 19.1 秒。

弑天下

首先考虑您将读取 CSV、JSON 的数据类型,以及将读取它的系统以及为什么?必须考虑所有这些细节。没有一种适合所有人的方式,最好的开发人员知道如何right tool使用job. 在不知道 ram 限制、数据等的情况下不清楚。我们会从服务器读取大量 JSON 吗?或者我们会解析一个小文本文件,通常每个函数都有一个目的。不要养成认为一种方式比另一种更好或更差的习惯,并限制你的学习和技能。读取文件的方法。文档解析从文件中读取所有数据并将其转换为对象。流解析一次读取一个元素,然后移动到下一个元素。有些方法可能更快,但它会将整个文件读入内存如果你的文件太大怎么办?或者如果您的文件不是那么大,寻找重复的名称怎么办?如果您逐行扫描文件,也许如果您正在搜索多个项目,那么逐行阅读是最好的方式吗?你应该看看这篇文章。特别感谢@Schwern,他已经在这里回答了您的问题。使用字节和扫描仪稍微快一些。见:链接I found that using scanner.Bytes() instead of scanner.Text() improves speed slightly on my machine.  bufio's scanner.Bytes() method doesn't allocate any additional memory, whereas Text() creates a string from its buffer.
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go