我正在将一个旧的小型 C 项目重写成 Go(以学习 Go)。
该项目基本上从文件中读取一些二进制数据,对所述数据进行一些过滤,然后将其打印到标准输出中。
代码的主要部分如下所示(省略错误处理):
type netFlowRow struct {
Timestamp uint32
Srcip [4]byte
Dstip [4]byte
Proto uint16
Srcport uint16
Dstport uint16
Pkt uint32
Size uint64
}
func main() {
// ...
file, _ := os.Open(path)
for j := 0; j < infoRow.Count; j++ {
netRow := netFlowRow{}
binary.Read(file, binary.BigEndian, &netRow)
// ...
fmt.Printf("%v", netRow)
}
}
在进行了天真的重写之后,go 版本的运行速度比 C 版本慢 10 倍(~40 秒对 2-3 秒)。我用 pprof 做了分析,它向我展示了这个:
(pprof) top10
39.96s of 40.39s total (98.94%)
Dropped 71 nodes (cum <= 0.20s)
Showing top 10 nodes out of 11 (cum >= 39.87s)
flat flat% sum% cum cum%
39.87s 98.71% 98.71% 39.87s 98.71% syscall.Syscall
0.09s 0.22% 98.94% 40.03s 99.11% encoding/binary.Read
0 0% 98.94% 39.87s 98.71% io.ReadAtLeast
0 0% 98.94% 39.87s 98.71% io.ReadFull
0 0% 98.94% 40.03s 99.11% main.main
0 0% 98.94% 39.87s 98.71% os.(*File).Read
0 0% 98.94% 39.87s 98.71% os.(*File).read
0 0% 98.94% 40.21s 99.55% runtime.goexit
0 0% 98.94% 40.03s 99.11% runtime.main
0 0% 98.94% 39.87s 98.71% syscall.Read
我没看错吗? syscall.Syscall 基本上是主要的时间消费者吗?它是从文件中读取的地方吗?
更新。 我使用了 bufio.Reader 并获得了这个配置文件:
(pprof) top10
34.16s of 36s total (94.89%)
Dropped 99 nodes (cum <= 0.18s)
Showing top 10 nodes out of 33 (cum >= 0.56s)
flat flat% sum% cum cum%
31.99s 88.86% 88.86% 32s 88.89% syscall.Syscall
0.43s 1.19% 90.06% 0.64s 1.78% runtime.mallocgc
0.39s 1.08% 91.14% 1.06s 2.94% encoding/binary.(*decoder).value
0.28s 0.78% 91.92% 0.99s 2.75% reflect.(*structType).Field
0.28s 0.78% 92.69% 0.28s 0.78% runtime.duffcopy
0.24s 0.67% 93.36% 1.64s 4.56% encoding/binary.sizeof
0.22s 0.61% 93.97% 34.51s 95.86% encoding/binary.Read
0.22s 0.61% 94.58% 0.22s 0.61% runtime.mach_semaphore_signal
0.07s 0.19% 94.78% 1.28s 3.56% reflect.(*rtype).Field
0.04s 0.11% 94.89% 0.56s 1.56% runtime.newobject
最佳答案
binary.Read 会比较慢,因为它使用了 reflection .我建议使用 bufio.Reader 进行基准测试并手动调用 binary.BigEndian 方法来读取您的结构:
type netFlowRow struct {
Timestamp uint32 // 0
Srcip [4]byte // 4
Dstip [4]byte // 8
Proto uint16 // 12
Srcport uint16 // 14
Dstport uint16 // 16
Pkt uint32 // 18
Size uint64 // 22
}
func main() {
// ...
file, _ := os.Open(path)
r := bufio.NewReader(file)
for j := 0; j < infoRow.Count; j++ {
var buff [4 + 4 + 4 + 2 + 2 + 2 + 4 + 8]byte
if _, err := io.ReadFull(r, buff[:]); err != nil {
panic(err)
}
netRow := netFlowRow{
Timestamp: binary.BigEndian.Uint32(buff[:4]),
// Srcip
// Dstip
Proto: binary.BigEndian.Uint16(buff[12:14]),
Srcport: binary.BigEndian.Uint16(buff[14:16]),
Dstport: binary.BigEndian.Uint16(buff[16:18]),
Pkt: binary.BigEndian.Uint32(buff[18:22]),
Size: binary.BigEndian.Uint64(buff[22:30]),
}
copy(netRow.Srcip[:], buff[4:8])
copy(netRow.Dstip[:], buff[8:12])
// ...
fmt.Printf("%v", netRow)
}
}
关于go - binary.Read 慢吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41400639/
CSV.open(name,"r").eachdo|row|putsrowend我得到以下错误:CSV::MalformedCSVErrorUnquotedfieldsdonotallow\ror\n文件名是一个.txt制表符分隔文件。我是专门做的。我有一个.csv文件,我转到excel,并将文件保存为.txt制表符分隔的文件。所以它是制表符分隔的。CSV.open不应该能够读取制表符分隔的文件吗? 最佳答案 尝试像这样指定字段分隔符:CSV.open("name","r",{:col_sep=>"\t"}).eachdo|row|
我在我正在处理的一些代码中发现了这一点。它旨在解决从磁盘读取key文件的要求。在生产环境中,key文件的内容位于环境变量中。旧代码:key=File.read('path/to/key.pem')新代码:key=File.read('|echo$KEY_VARIABLE')这是如何工作的? 最佳答案 来自IOdocs:Astringstartingwith“|”indicatesasubprocess.Theremainderofthestringfollowingthe“|”isinvokedasaprocesswithappro
我有这个代码File.open(file_name,'r'){|file|file.read}但是Rubocop发出警告:Offenses:Style/SymbolProc:Pass&:readasargumenttoopeninsteadofablock.你是怎么做到的? 最佳答案 我刚刚创建了一个名为“t.txt”的文件,其中包含“Hello,World\n”。我们可以按如下方式阅读。File.open('t.txt','r',&:read)#=>"Hello,World\n"顺便说一下,由于第二个参数的默认值是'r',所以这样
我有以下代码,它下载一个文件,然后将文件的内容读入一个变量。使用该变量,它执行一个命令。这个配方不会收敛,因为/root/foo在编译阶段不存在。我可以通过多个聚合和一个来解决这个问题ifFile.exist但我想用一个收敛来完成它。关于如何做到这一点有什么想法吗?execute'download_joiner'docommand"awss3cps3://bucket/foo/root/foo"not_if{::File.exist?('/root/foo')}endpassword=::File.read('/root/foo').chompexecute'join_domain'd
标题本身就说明了......read_timeout和open_timeout之间有什么区别? 最佳答案 open_timeout是您愿意等待“打开连接”的时间。在TCP上下文中,在放弃尝试并引发超时错误之前等待握手完成的时间量。read_timeout您可能会猜到,是您愿意等待从连接方接收到某些数据的时间。一个例子可能会清楚地说明这一点:在SOAPoverHTTPoverTCP上下文中(简化):您尝试与服务器建立TCP连接。如果建立连接的时间比open_timeout长,则放弃连接尝试并引发/发出/返回超时错误。如果连接成功,您发
在Railcasts上,我注意到一个非常有趣的功能“转到符号”窗口。它像Command-T一样工作,但显示当前文件中可用的类和方法。如何在vim中获取它? 最佳答案 尝试:helptags有各种程序和脚本可以生成标记文件。此外,标记文件格式非常简单,因此很容易将sed(1)或类似的脚本组合在一起,无论您使用何种语言,它们都可以生成标记文件。轻松获取标记文件(除了下载生成器之外)的关键在于格式化样式而不是实际解析语法。 关于ruby-on-rails-Textmate'Gotosymbol
我正在处理oauth1.0(twitter和flickr)。网站工作在80端口,oauth服务器工作在8080端口算法:向oauth服务器发送ajax请求以检查用户是否有有效的access_token如果用户没有access_token或access_token已过期,则打开授权窗口在oauth服务器的用户session中保存access_token发送分享数据到oauth服务器它使用sinatra+rack:session+rack::session::sequel+sqlite来存储session。它在每个响应中发送Set-Cookie:rack.session=id我正在使用2种
有人知道为什么我的rails3.0.7cli这么慢吗?当我运行railss或railsg时,他大约需要5秒才能真正执行命令...有什么建议吗?谢谢 最佳答案 更新:我正在将我的建议从rrails切换到rails-sh,因为前者支持REPL,而rrails不是用例。此外,当与ruby环境结合使用时,修补似乎确实可以提高性能变量,现在反射(reflect)在答案中。一个可能的原因可能是这个performancebuginruby每当在ruby代码中使用“require”时,它就会调用一些代码(更多详细信息here)。在使用Rai
我已尽我所能搜索互联网以解决此问题,但我完全被关键字!binary所吸引,因为搜索引擎(包括stackoverflow的内部搜索!)去掉了感叹号。我正在http://ruby.railstutorial.org学习Rails教程-这在很大程度上是一个很好的资源。我的application.html.erb页面底部有一个有用的东西:我被告知特定场景应该输出以下内容:---!map:ActiveSupport::HashWithIndifferentAccesscommit:Signinsession:!ActiveSupport::HashWithIndifferentAccesspas
我有:o=File.new("ouput.txt","rw+")File.new("my_file.txt").lines.reverse_each{|line|?????line}o.close不知道用什么方法写入文件输出o 最佳答案 puts理解数组,因此您可以将其简化为:File.open("f2.txt","w"){|o|o.putsFile.readlines("f1.txt").reverse} 关于ruby-简单的问题:Readfile,在Ruby中反转它并写入另一个文件,