gpt4 book ai didi

go - 多次执行例程读取pcap文件不能提高性能吗?

转载 作者:行者123 更新时间:2023-12-01 20:23:48 26 4
gpt4 key购买 nike

我需要阅读约600个pcap文件,每个文件约为100MB。
我使用gopacket加载pcap文件并进行检查。

Case1: uses 1 routine to check.


Case2: uses 40 routines to check.


而且我发现case1和case2消耗的时间相似。
区别是case1的cpu使用率只有200%,而case2可以达到3000%。
我的问题是为什么多个例程不能提高性能?
代码中有一些注释,希望对您有所帮助。
package main

import (
"flag"
"fmt"
"io/ioutil"
"log"
"os"
"strings"
"sync"

"github.com/google/gopacket"
"github.com/google/gopacket/layers"
"github.com/google/gopacket/pcap"
)

func main() {
var wg sync.WaitGroup

var dir = flag.String("dir", "../pcap", "input dir")
var threadNum = flag.Int("threads", 40, "input thread number")
flag.Parse()
fmt.Printf("dir=%s, threadNum=%d\n", *dir, *threadNum)

pcapFileList, err := ioutil.ReadDir(*dir)
if err != nil {
panic(err)
}

log.Printf("start. file number=%d.", len(pcapFileList))

fileNumPerRoutine := len(pcapFileList) / *threadNum
lastFileNum := len(pcapFileList) % *threadNum

// split files to different routine
// each routine only process files which belong to itself
if fileNumPerRoutine > 0 {
for i := 0; i < *threadNum; i++ {
start := fileNumPerRoutine * i
end := fileNumPerRoutine * (i + 1)
if lastFileNum > 0 && i == (*threadNum-1) {
end = len(pcapFileList)
}
// fmt.Printf("start=%d, end=%d\n", start, end)
wg.Add(1)
go checkPcapRoutine(i, &wg, dir, pcapFileList[start:end])
}
}

wg.Wait()
log.Printf("end.")
}

func checkPcapRoutine(id int, wg *sync.WaitGroup, dir *string, pcapFileList []os.FileInfo) {
defer wg.Done()

for _, p := range pcapFileList {
if !strings.HasSuffix(p.Name(), "pcap") {
continue
}
pcapFile := *dir + "/" + p.Name()
log.Printf("checkPcapRoutine(%d): process %s.", id, pcapFile)

handle, err := pcap.OpenOffline(pcapFile)
if err != nil {
log.Printf("error=%s.", err)
return
}
defer handle.Close()

packetSource := gopacket.NewPacketSource(handle, handle.LinkType())

// Per my test, if I don't parse packets, it is very fast, even use only 1 routine, so IO should not be the bottleneck.
// What puzzles me is that every routine has their own packets, each routine is independent, but it still seems to be processed serially.
// This is the first time I use gopacket, maybe used wrong parameter?
for packet := range packetSource.Packets() {
gtpLayer := packet.Layer(layers.LayerTypeGTPv1U)
lays := packet.Layers()
outerIPLayer := lays[1]
outerIP := outerIPLayer.(*layers.IPv4)

if gtpLayer == nil && (outerIP.Flags&layers.IPv4MoreFragments != 0) && outerIP.Length < 56 {
log.Panicf("file:%s, idx=%d may leakage.", pcapFile, j+1)
break
}
}
}
}

最佳答案

为了并行运行两个或多个任务,执行这些任务所需的操作必须具有不依赖于彼此或某些外部资源的属性,这些资源随后被这些任务共享。
在现实世界中,真正完全独立的任务很少见(如此罕见,甚至有专门的名称来描述此类任务:它们被称为embarrasingly parallel),但是当任务对彼此的进度有一定的依赖性时并且争夺访问共享资源的权限低于某个阈值,因此添加更多的“ worker ”(goroutine)可以改善完成一组任务所需的总时间。
请在此处注意“可能”:例如,您的存储设备及其上的文件系统以及与该文件系统一起工作的内核数据结构和代码是所有goroutine必须访问的共享介质。这种介质在吞吐量和延迟方面都有一定的限制。基本上,您只能每秒从该介质读取M字节-不管您是单个读取器充分利用了该带宽,还是N个读取器-每个读取器都利用了大约M/N的带宽,这无关紧要:读取速度不能超过M BPS的限制。
此外,在现实世界中最常发现的资源在争用时往往会降低其性能:例如,如果必须访问该资源locked,则积极地希望获取您拥有的锁的访问者越多,则花费的CPU时间就越多。在锁管理代码中(当资源更复杂时,例如“存储设备上的FS,全部由内核管理”的复杂内容的联合体,则成为分析并发访问时它如何退化的方法)更复杂)。
TL; DR
我可以得出一个有根据的猜测,因为goroutine必须读取文件,所以您的任务只是受I/O约束。
您可以通过修改代码以首先将所有文件提取到内存中,然后将缓冲区交给解析goroutine进行验证。
在这种情况下,您所观察到的大量CPU支出是一个红鲱鱼:当代系统喜欢将100%CPU利用率视为“完全利用单个硬件处理线程”,因此,如果您拥有4个CPU内核,启用HyperThreading™(或AMD为此提供的任何支持)后,系统的全部容量为4×2 = 8或800%。
您所看到的事实可能超出了理论能力(我们不知道),这可能是由于您的系统显示了所谓的“饥饿”的原因:您有许多软件线程想要执行,但要等待它们CPU时间,并且系统显示为疯狂的CPU利用率。

关于go - 多次执行例程读取pcap文件不能提高性能吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63502032/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com