亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

優化Go文件讀取程序

優化Go文件讀取程序

Go
九州編程 2021-05-07 15:14:38
我正在嘗試處理一個日志文件,其每一行看起來像這樣:flow_stats: 0.30062869162666672 gid 0 fid 1 pkts 5.0 fldur 0.30001386666666674 avgfldur 0.30001386666666674 actfl 3142 avgpps 16.665896331902879 finfl 1我對這個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')}請注意,實際上我確實err在循環中檢查了s-為了簡潔起見,我省略了它。 google-pprof表明大部分時間被消耗在strings.Fields用strings.FieldsFunc,unicode.IsSpace和runtime.stringiter2。我怎樣才能使它運行得更快?
查看完整描述

1 回答

?
慕哥6287543

TA貢獻1831條經驗 獲得超10個贊

更換


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和字段不相同。字段假定標記由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))

}

并輸出:


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


查看完整回答
反對 回復 2021-05-17
  • 1 回答
  • 0 關注
  • 293 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號