Go 是二进制的,读得慢吗?

Go 是二进制的,读得慢吗?,go,Go,我正在将一个旧的小型C项目改写为Go(学习Go) 该项目基本上从文件中读取一些二进制数据,对所述数据进行过滤,然后将其打印到标准输出 代码的主要部分如下所示(省略错误处理): 类型netFlowRow结构{ 时间戳uint32 Srcip[4]字节 Dstip[4]字节 原始uint16 SRCUINT16端口 DStunit16端口 单元32 尺寸uint64 } func main(){ // ... 文件:=os.Open(路径) 对于j:=0;j

我正在将一个旧的小型C项目改写为Go(学习Go)

该项目基本上从文件中读取一些二进制数据,对所述数据进行过滤,然后将其打印到标准输出

代码的主要部分如下所示(省略错误处理):

类型netFlowRow结构{
时间戳uint32
Srcip[4]字节
Dstip[4]字节
原始uint16
SRCUINT16端口
DStunit16端口
单元32
尺寸uint64
}
func main(){
// ...
文件:=os.Open(路径)
对于j:=0;j
在完成一次简单的重写后,go版本的运行速度比C版本慢10倍(大约40秒vs 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
(pprof)top10
39.96秒,共40.39秒(98.94%)
丢弃71个节点(cum=39.87s)
单位百分比总和百分比总和百分比
39.87S98.71%98.71%39.87S98.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.Read至少
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。(*文件)。读取
0 0%98.94%39.87s 98.71%os。(*文件)。读取
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基本上是主要的时间使用者吗?这是从文件读取的地方吗

Upd。 我使用了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
(pprof)top10
34.16秒,共36秒(94.89%)
丢弃99个节点(cum=0.56s)
单位百分比总和百分比总和百分比
31.99S88.86%88.86%32S88.89%syscall.syscall
0.43s1.19%90.06%0.64s1.78%runtime.mallocgc
0.39s1.08%91.14%1.06s2.94%编码/二进制。(*解码器)。值
0.28s 0.78%91.92%0.99s 2.75%反射。(*structType).字段
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_信号量
0.07s 0.19%94.78%1.28s 3.56%reflect.(*rtype).字段
0.04s 0.11%94.89%0.56s 1.56%runtime.newobject

二进制。由于它使用二进制文件,因此读取
的速度会较慢。我建议使用
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)
    }
}
类型netFlowRow结构{
时间戳uint32//0
Srcip[4]字节//4
Dstip[4]字节//8
原型uint16//12
Srcport uint16//14
数据端口uint16//16
单元32//18
尺寸uint64//22
}
func main(){
// ...
文件:=os.Open(路径)
r:=bufio.NewReader(文件)
对于j:=0;j
二进制。由于它使用二进制文件,因此读取
的速度会较慢。我建议使用
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)
    }
}
类型netFlowRow结构{
时间戳uint32//0
Srcip[4]字节//4
Dstip[4]字节//8
原型uint16//12
Srcport uint16//14
数据端口uint16//16
单元32//18
尺寸uint64//22
}
func main(){
// ...
文件:=os.Open(路径)
r:=bufio.NewReader(文件)
对于j:=0;j
是的,这个文件大约是1GB,这将是二进制文件的开销。我建议对这两种方法进行基准测试:(a)使用
bufio.Reader
而不是直接从文件中读取,以及(b)使用
binary.BigEndian.*
方法直接读取字段,而不是整个结构上的
binary.read
。您的C程序是否使用了文件*,例如调用fread()?如果是这样的话,你应该将文件包装在一个bufio.Reader中,这样你就可以像C程序一样进行缓冲读取。我已经用
bufio.Reader
C程序使用的文件*更新了这个问题,是的。是的,这个文件大约是1GB。按照它的用法,
binary.Read
。我建议基准测试