为什么 Go 中读写文件比 Perl 慢很多?这是很多开发者在使用这两种编程语言时经常遇到的问题。在这篇文章中,php小编草莓将为您解答这个问题。在比较 Go 和 Perl 读写文件的速度时,我们需要考虑到两个关键因素:语言特性和底层实现。Go 语言在文件读写方面的设计理念与 Perl 不同,这导致了它们在性能上的差异。同时,底层实现也是影响读写速度的重要因素。接下来,我们将详细分析这些因素,帮助您更好地理解为什么 Go 中读写文件比 Perl 慢很多。
问题内容
我使用go是为了提高代码效率,但是当我使用go读写文件时,发现它的读写效率没有perl高。是我代码的问题还是其他原因?
构建输入文件:
# input file:
for i in $(seq 1 600000) do echo server$((random%800+100)),$random,$random,$random >> sample.csv done
用perl读写文件:
time cat sample.csv | perl -ne 'chomp;print"$_"' > out.txt
real 0m0.249s
user 0m0.083s
sys 0m0.049s
使用 go 读写文件:
package main
import (
"bufio"
"fmt"
"io"
"os"
"strings"
)
func main() {
filepath := "./sample.csv"
file, err := os.openfile(filepath, os.o_rdwr, 0666)
if err != nil {
fmt.println("open file error!", err)
return
}
defer file.close()
buf := bufio.newreader(file)
for {
line, err := buf.readstring('\n')
line = strings.trimspace(line)
fmt.println(line)
if err != nil {
if err == io.eof {
fmt.println("file read ok!")
break
} else {
fmt.println("read file error!", err)
return
}
}
}
}
然后我运行:
time go run read.go > out.txt
real 0m2.332s
user 0m0.326s
sys 0m2.038s
为什么 go 的读写速度比 perl 慢近 10 倍?
解决方法
您正在将苹果与橙子进行比较。
至少有两个方法错误:
您的 perl 咒语测量
cat
如何读取文件并通过pipe(2) 发送其内容
,而perl
从那里读取数据,对其进行处理并将结果写入其标准输出。你的围棋咒语
- 测量 go 工具链的完整构建过程(包括编译、链接和写出可执行映像文件)然后运行 已编译程序的组成部分,以及
- 测量对标准输出的无缓冲写入(
fmt.print*
调用),而在 perl 代码中写入标准输出 - 引用 文档 - “如果输出到终端,通常可以进行行缓冲,否则进行块缓冲。”
让我们尝试比较一下苹果。
首先,这是一个类似的 go 实现:
package main
import (
"bufio"
"bytes"
"fmt"
"os"
)
func main() {
in := bufio.newscanner(os.stdin)
out := bufio.newwriter(os.stdout)
for in.scan() {
s := bytes.trimspace(in.bytes())
if _, err := out.write(s); err != nil {
fmt.fprint(os.stderr, "failed to write file:", err)
os.exit(1)
}
}
if err := out.flush(); err != nil {
fmt.fprint(os.stderr, "failed to write file:", err)
os.exit(1)
}
if err := in.err(); err != nil {
fmt.fprint(os.stderr, "reading failed:", err)
os.exit(1)
}
}
让我们将其保存为 chomp.go
并进行测量:
构建代码:
$ go build chomp.go
生成输入文件:
$ for i in $(seq 1 600000);执行 echo server$((random%800+100)),$random,$random,$random;完成 >sample.csv
运行 perl 代码:
$ time { perl -ne 'chomp; print "$_";'
out1.txt; } real 0m0.226s user 0m0.102s sys 0m0.048s 再次运行它以确保它已从文件系统缓存中读取输入文件:
$ time { perl -ne 'chomp; print "$_";'
out1.txt; } real 0m0.123s user 0m0.090s sys 0m0.033s 注意执行时间是如何减少的。
在缓存的输入上运行 go 代码:
$ time { ./chomp
out2.txt; } real 0m0.063s user 0m0.032s sys 0m0.032s -
确保结果相同:
$ cmp out1.txt out2.txt
如您所见,在我的带有 ssd 的 linux/amd64
系统上,结果大致相同。
嗯,我还应该指出,为了获得合理的结果,您需要运行每个命令,例如 1000 次,并对每个批次中的结果进行平均,然后比较这些数字,但我认为这足以证明什么您的方法存在的问题是。
还有一件事需要考虑:这两个程序的运行时间绝大多数由文件系统 i/o 主导,因此,如果您认为 go 会更快,那么您的期望是没有根据的:这两个程序大部分时间sleep 在内核的系统调用 read(2)
和 write(2)
。在某些涉及 cpu 运算的情况下,go 程序可能比 perl 程序更快(特别是如果它是为利用多核系统而编写的),但您的示例根本不是这种情况。
哦,只是为了明确未说明的事实:虽然 go 语言规范没有说明 aot,而 go run
是一种针对一次性一次性演出的 hack,不严肃的工作,也不执行任何严重复杂程度的代码。简而言之,go-that-you-are-using 并不是一种解释性语言,尽管 go run
的可用性可能使它看起来如此。事实上,它执行正常 go build
会执行的操作,然后运行生成的可执行文件,然后将其丢弃。
您可能会想说 perl 也处理“源代码”,但 perl 解释器针对处理脚本和 go 的构建工具链进行了高度优化——同时与大多数其他编译语言相比速度快得惊人——未针对此进行优化。
可能更明显的区别是,perl 解释器实际上解释您的(非常简单的)脚本,而 chomp
和 print
是所谓的“内置函数”,很容易提供给由解释器执行脚本。与构建 go 程序相比,编译器解析源代码文件并将其转换为机器代码,链接器实际上读取 go 标准库的编译包的文件 - 所有这些都是 import
ed, - 从它们,组合所有这些机器代码并写出一个可执行图像文件(这很像 perl
二进制文件本身!);当然,这是一个非常消耗资源的过程,与实际的程序执行无关。
以上就是为什么 Go 中读写文件比 Perl 慢很多?的详细内容,更多请关注编程网其它相关文章!