gpt4 book ai didi

performance - 为什么与strconv.Atoi相比,strconv.ParseUint这么慢?

转载 作者:行者123 更新时间:2023-12-03 10:09:45 31 4
gpt4 key购买 nike

我正在使用以下代码对从stringintuint的编码进行基准测试:

package main

import (
"strconv"
"testing"
)

func BenchmarkUnmarshalInt(b *testing.B) {
for i := 0; i < b.N; i++ {
UnmarshalInt("123456")
}
}

func BenchmarkUnmarshalUint(b *testing.B) {
for i := 0; i < b.N; i++ {
UnmarshalUint("123456")
}
}

func UnmarshalInt(v string) int {
i, _ := strconv.Atoi(v)
return i
}

func UnmarshalUint(v string) uint {
i, _ := strconv.ParseUint(v, 10, 64)
return uint(i)
}
结果:
Running tool: C:\Go\bin\go.exe test -benchmem -run=^$ myBench/main -bench .

goos: windows
goarch: amd64
pkg: myBench/main
BenchmarkUnmarshalInt-8 99994166 11.7 ns/op 0 B/op 0 allocs/op
BenchmarkUnmarshalUint-8 54550413 21.0 ns/op 0 B/op 0 allocs/op
第二个( uint)的速度几乎是第一个( int)的两倍吗?

最佳答案

是的,有可能。当输入的字符串长度小于19时,strconv.Atoi具有快速路径(如果int为32位,则为10)。这使它更快,因为它不需要检查溢出。
如果将测试编号更改为“1234567890123456789”(假设为64位int),则int基准测试会比uint基准测试稍慢,因为无法使用快速路径。在我的机器上,签名版本需要37.6 ns/op,而未签名版本需要31.5 ns/op。
这是修改后的基准代码(请注意,我添加了一个变量,用于汇总分析结果,以防编译器变得聪明并对其进行优化)。

package main

import (
"fmt"
"strconv"
"testing"
)

const X = "1234567890123456789"

func BenchmarkUnmarshalInt(b *testing.B) {
var T int
for i := 0; i < b.N; i++ {
T += UnmarshalInt(X)
}
fmt.Println(T)
}

func BenchmarkUnmarshalUint(b *testing.B) {
var T uint
for i := 0; i < b.N; i++ {
T += UnmarshalUint(X)
}
fmt.Println(T)
}

func UnmarshalInt(v string) int {
i, _ := strconv.Atoi(v)
return i
}

func UnmarshalUint(v string) uint {
i, _ := strconv.ParseUint(v, 10, 64)
return uint(i)
}
作为引用,当前标准库中 strconv.Atoi 的代码如下:
func Atoi(s string) (int, error) {
const fnAtoi = "Atoi"

sLen := len(s)
if intSize == 32 && (0 < sLen && sLen < 10) ||
intSize == 64 && (0 < sLen && sLen < 19) {
// Fast path for small integers that fit int type.
s0 := s
if s[0] == '-' || s[0] == '+' {
s = s[1:]
if len(s) < 1 {
return 0, &NumError{fnAtoi, s0, ErrSyntax}
}
}

n := 0
for _, ch := range []byte(s) {
ch -= '0'
if ch > 9 {
return 0, &NumError{fnAtoi, s0, ErrSyntax}
}
n = n*10 + int(ch)
}
if s0[0] == '-' {
n = -n
}
return n, nil
}

// Slow path for invalid, big, or underscored integers.
i64, err := ParseInt(s, 10, 0)
if nerr, ok := err.(*NumError); ok {
nerr.Func = fnAtoi
}
return int(i64), err
}

关于performance - 为什么与strconv.Atoi相比,strconv.ParseUint这么慢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64513411/

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