为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

Go
慕森王 2022-07-11 15:55:19
我正在学习如何在 Go 中有效地读取非常大的文件。我已经尝试过bufio.NewScanner并bufio.NewReader使用ReadString('\n'). 在这两个选项中,NewScanner似乎始终更快(2:1)。因为NewScanner我发现逐行读取文件比运行 unix cat 命令读取文件需要更多时间。我测量了运行这段代码需要多长时间:package mainimport (    "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 中逐行读取文件的最有效方法。
查看完整描述

2 回答

?
30秒到达战场

TA贡献1828条经验 获得超6个赞

根据 MuffinTop 的评论,这是提高速度的代码片段。性能损失与 Scanner 的使用无关,而是与以下事实有关:

  1. 不在输出中使用缓冲

  2. 使用scanner.Text()-which 分配一个字符串 - 而不是scanner.Bytes()

添加输出缓冲的性能:

package main


import (

    "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 main


import (

    "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 秒。


查看完整回答
反对 回复 2022-07-11
?
弑天下

TA贡献1818条经验 获得超8个赞

首先考虑您将读取 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.


查看完整回答
反对 回复 2022-07-11
  • 2 回答
  • 0 关注
  • 414 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号