如何基于修改其输入的函数



当我基准修改其输入的函数时,我必须为基准的每个循环复制测试数据,并在这样做时暂停计时器。这可能意味着,如果我运行go test -bench MyTest -benchtime 1s,测试可能需要2分钟而不是1秒钟。

我做错了什么,还是我只需要忍受?


更多上下文:

我正在编写一个用于读取系统日志日志的程序。我记录范式的一部分是记录消息的第一行包含可读文本,并且以下行包含"额外信息",例如堆栈跟踪。因此,我的日志读取器(除其他外)将消息分配在第一行休息中,rsyslog逃到了#012

这是为此的代码:

// Splits the main line from extra information
func splitMessageExtra(line *string) string {
    var prev rune
    for i, char := range *line {
        if prev == 0 && char == '#' {
            prev = char
            continue
        }
        if prev == '#' && char == '0' {
            prev = char
            continue
        }
        if prev == '0' && char == '1' {
            prev = char
            continue
        }
        if prev == '1' && char == '2' {
            extra := (*line)[i+1:]
            *line = (*line)[0 : i-3]
            return extra
        }
        prev = 0
    }
    return ""
}

它最初使用strings.Split并返回了新字符串,但是CPU分析表明它太慢了。

这是基准函数:

var testMessage = `Feb 10 15:16:20 foo_stats[-] (warning): [foo_stats.postfix, line 166, thread "processor_mta03"]: Skipped line because there is no context:#012Feb 10 15:16:20 mta03 postfix/qmgr[7419]: ABCDEF123: from=<>, size=24431, nrcpt=1 (queue active)`
func BenchmarkSplitMessageExtra(b *testing.B) {
    for i := 0; i < b.N; i++ {
        b.StopTimer()
        msg := string([]byte(testMessage))
        b.StartTimer()
        splitMessageExtra(&msg)
    }
}

这是一个不暂停计时器的跑步:

$ GO TEST -BENCH SPLITMESSAGEEXTRA -BENCHTIME 1SBenchmarkssplitMessageExtra-8 3000000 434 NS/OP经过OK github.com/hubro/logreader 1.730s

这是一个具有上述基准功能的运行:

$ GO TEST -BENCH SPLITMESSAGEEXTRA -BENCHTIME 1SBenchmarkssplitMessageExtra-8 5000000 385 NS/OP经过OK github.com/hubro/logreader 100.563s

请注意,运行需要年龄。

您的代码和基准似乎很慢。这是一个更快的版本。

package main
import (
    "strings"
    "testing"
)
// Splits the main line from extra information
func splitMessageExtra(line *string) string {
    const newline = "#012"
    i := strings.Index(*line, newline)
    if i < 0 {
        return ""
    }
    extra := (*line)[i+len(newline):]
    *line = (*line)[0:i]
    return extra
}
var testMessage = `Feb 10 15:16:20 foo_stats[-] (warning): [foo_stats.postfix, line 166, thread "processor_mta03"]: Skipped line because there is no context:#012Feb 10 15:16:20 mta03 postfix/qmgr[7419]: ABCDEF123: from=<>, size=24431, nrcpt=1 (queue active)`
func BenchmarkSplitMessageExtra(b *testing.B) {
    for i := 0; i < b.N; i++ {
        msg := testMessage
        splitMessageExtra(&msg)
    }
}

输出:

$ go test -bench=.
goos: linux
goarch: amd64
pkg: extra
BenchmarkSplitMessageExtra-4    50000000            32.2 ns/op
PASS
ok      extra   1.647s

进行比较,这是您的代码和基准的结果。您的代码和基准分别比我的:968 NS/OP和50.184s对32.2 NS/OP和1.647S。

package main
import (
    "testing"
)
// Splits the main line from extra information
func splitMessageExtra(line *string) string {
    var prev rune
    for i, char := range *line {
        if prev == 0 && char == '#' {
            prev = char
            continue
        }
        if prev == '#' && char == '0' {
            prev = char
            continue
        }
        if prev == '0' && char == '1' {
            prev = char
            continue
        }
        if prev == '1' && char == '2' {
            extra := (*line)[i+1:]
            *line = (*line)[0 : i-3]
            return extra
        }
        prev = 0
    }
    return ""
}
var testMessage = `Feb 10 15:16:20 foo_stats[-] (warning): [foo_stats.postfix, line 166, thread "processor_mta03"]: Skipped line because there is no context:#012Feb 10 15:16:20 mta03 postfix/qmgr[7419]: ABCDEF123: from=<>, size=24431, nrcpt=1 (queue active)`
func BenchmarkSplitMessageExtra(b *testing.B) {
    for i := 0; i < b.N; i++ {
        b.StopTimer()
        msg := string([]byte(testMessage))
        b.StartTimer()
        splitMessageExtra(&msg)
    }
}

输出:

$ go test -bench=.
goos: linux
goarch: amd64
pkg: extra
BenchmarkSplitMessageExtra-4     2000000           968 ns/op    
PASS
ok      extra   50.184s

您的某些代码是不必要的;它使用CPU时间并触发分配。例如,将for i, char := range *line {}转换为runes,将string转换为 []byte转换为 stringstring([]byte(testMessage))。一些算法可以改进。例如,搜索新线。

没有错。StopTimerStartTimer应该比splitMessageExtra贵得多。他们俩都致电runtime.ReadMemStats。请参阅此处。

相关内容

  • 没有找到相关文章

最新更新