我正在尝试处理一个日志文件,其每一行看起来像这样:
flow_stats: 0.30062869162666672 gid 0 fid 1 pkts 5.0 fldur 0.30001386666666674 avgfldur 0.30001386666666674 actfl 3142 avgpps 16.665896331902879 finfl 1
Run Code Online (Sandbox Code Playgroud)
我对这个pkts领域和fldur领域很感兴趣.我有一个可以读取百万行日志文件的Python脚本,为所有不同持续时间的每个数据包创建一个列表,对这些列表进行排序并在大约3秒内计算出中值.
我正在玩Go编程语言,并认为我会重写它,希望它运行得更快.
到目前为止,我一直很失望.只需将文件读入数据结构大约需要5.5秒.所以我想知道你们中的一些人是否可以帮助我更快地完成这项工作(呵呵).
这是我的循环:
data := make(map[int][]float32)
infile, err := os.Open("tmp/flow.tr")
defer infile.Close()
if err != nil {
panic(err)
}
reader := bufio.NewReader(infile)
line, err := reader.ReadString('\n')
for {
if len(line) == 0 {
break
}
if err != nil && err != io.EOF {
panic(err)
}
split_line := strings.Fields(line)
num_packets, err := strconv.ParseFloat(split_line[7], 32)
duration, err := strconv.ParseFloat(split_line[9], 32)
data[int(num_packets)] = append(data[int(num_packets)], float32(duration))
line, err = reader.ReadString('\n')
}
Run Code Online (Sandbox Code Playgroud)
请注意,我确实检查了err循环中的s - 为简洁起见,我省略了它. google-pprof表明大部分时间被消耗在strings.Fields用strings.FieldsFunc,unicode.IsSpace和runtime.stringiter2.
如何让这个运行得更快?
更换
split_line := strings.Fields(line)
同
split_line := strings.SplitN(line, " ", 11)
在1M线随机生成的文件上提高了约4倍的速度,该文件模仿了您在上面提供的格式:
strings.Fields版本:已于4.232525975s完成
strings.SplitN版本:已在1.111450755s中完成
一些效率来自于能够在分割持续时间之后避免解析和分割输入行,但其中大部分来自SplitN中更简单的分裂逻辑.即使拆分所有字符串也不会比持续时间后停止更长的时间.使用:
split_line := strings.SplitN(line, " ", -1)
完成于1.554971313s
SplitN和Fields不一样.Fields假定标记由1个或多个空格字符限定,其中SplitN将标记视为由分隔符字符串限定的任何内容.如果您的输入在标记之间有多个空格,则split_line将包含每对空格的空标记.
排序和计算中位数不会增加太多时间.在排序时,为了方便起见,我将代码更改为使用float64而不是float32.这是完整的程序:
package main
import (
"bufio"
"fmt"
"os"
"sort"
"strconv"
"strings"
"time"
)
// SortKeys returns a sorted list of key values from a map[int][]float64.
func sortKeys(items map[int][]float64) []int {
keys := make([]int, len(items))
i := 0
for k, _ := range items {
keys[i] = k
i++
}
sort.Ints(keys)
return keys
}
// Median calculates the median value of an unsorted slice of float64.
func median(d []float64) (m float64) {
sort.Float64s(d)
length := len(d)
if length%2 == 1 {
m = d[length/2]
} else {
m = (d[length/2] + d[length/2-1]) / 2
}
return m
}
func main() {
data := make(map[int][]float64)
infile, err := os.Open("sample.log")
defer infile.Close()
if err != nil {
panic(err)
}
reader := bufio.NewReaderSize(infile, 256*1024)
s := time.Now()
for {
line, err := reader.ReadString('\n')
if len(line) == 0 {
break
}
if err != nil {
panic(err)
}
split_line := strings.SplitN(line, " ", 11)
num_packets, err := strconv.ParseFloat(split_line[7], 32)
if err != nil {
panic(err)
}
duration, err := strconv.ParseFloat(split_line[9], 32)
if err != nil {
panic(err)
}
pkts := int(num_packets)
data[pkts] = append(data[pkts], duration)
}
for _, k := range sortKeys(data) {
fmt.Printf("pkts: %d, median: %f\n", k, median(data[k]))
}
fmt.Println("\nCompleted in ", time.Since(s))
}
Run Code Online (Sandbox Code Playgroud)
并输出:
pkts: 0, median: 0.498146
pkts: 1, median: 0.511023
pkts: 2, median: 0.501408
...
pkts: 99, median: 0.501517
pkts: 100, median: 0.491499
Completed in 1.497052072s
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
294 次 |
| 最近记录: |