Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

优化生成随机字符串 #154

Merged
merged 1 commit into from
Jan 31, 2024
Merged

优化生成随机字符串 #154

merged 1 commit into from
Jan 31, 2024

Conversation

pigwantacat
Copy link
Contributor

优化随机字符串生成

背景

原来的随机字符串生成代码在Windows环境下就存在BUG,可参考Function RandomChars has bug · Issue #121 · gookit/goutil (github.com)

在Windows本地测试发现如果使用for循环重复生成随机字符串存在相同的情况,代码如下:

func main() {
	for i := 0; i < 10; i++ {
		println(strutil.RandomCharsV3(10))
	}
}

输出打印如下:

GOROOT=C:\Users\zhb15\sdk\go1.21.3 #gosetup
GOPATH=D:\Go\WorkSpace #gosetup
C:\Users\zhb15\sdk\go1.21.3\bin\go.exe build -o C:\Users\zhb15\AppData\Local\JetBrains\GoLand2023.3\tmp\GoLand\___go_build_mytest_com_zhb_utils.exe mytest/com/zhb/utils #gosetup
C:\Users\zhb15\AppData\Local\JetBrains\GoLand2023.3\tmp\GoLand\___go_build_mytest_com_zhb_utils.exe
p35cdB4ntT
p35cdB4ntT
p35cdB4ntT
p35cdB4ntT
p35cdB4ntT
p35cdB4ntT
p35cdB4ntT
qgHpMOu2R6
qgHpMOu2R6
qgHpMOu2R6

进程 已完成,退出代码为 0

正好最近看到一篇关于随机字符串生成的文章,原文链接:Golang生成随机字符串的八种方式与性能测试-云社区-华为云 (huaweicloud.com)How to generate a random string of a fixed length in Go? - Stack Overflow

所以打算根据文章中提到的方法优化strutil的随机字符串生成方法

实现

新增的方法有2个nearestPowerOfTwobuildRandomStringnearestPowerOfTwo方法是求大于等于字符模板的最近的2的整数次幂,这个方法参考java8的hashmap的tableSizeFor函数,可参考文章:HashMap部分源码简析 | 柳门竹巷 (zhbblog.top)

/**
 * Returns a power of two size for the given target capacity.
 */
//返回大于输入参数且最近的2的整数次幂的数。比如10,则返回16
static final int tableSizeFor(int cap) {
    int n = cap - 1;
    n |= n >>> 1;
    n |= n >>> 2;
    n |= n >>> 4;
    n |= n >>> 8;
    n |= n >>> 16;
    return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
}

buildRandomString主要用于根据输入的字符串模板,生成指定长度的随机字符串,具体原理请参考上诉链接

结果

测试结果

现在在Windows本地测试结果如下,代码:

func main() {
	for i := 0; i < 10; i++ {
		println(testUtil.RandomCharsV3(10))
	}
}

输出打印如下:

GOROOT=C:\Users\zhb15\sdk\go1.21.3 #gosetup
GOPATH=D:\Go\WorkSpace #gosetup
C:\Users\zhb15\sdk\go1.21.3\bin\go.exe build -o C:\Users\zhb15\AppData\Local\JetBrains\GoLand2023.3\tmp\GoLand\___go_build_mytest_com_zhb_utils.exe mytest/com/zhb/utils #gosetup
C:\Users\zhb15\AppData\Local\JetBrains\GoLand2023.3\tmp\GoLand\___go_build_mytest_com_zhb_utils.exe
e4dKh62ENr
cZfsXSTxhB
n8lGE8rE7f
ftiDJX8NHU
viz89Ur6Bb
j469ymTSQr
fyfcHHeHvq
wDoZelPwlL
BzRHQSgPIN
LzybA6Jz1e

进程 已完成,退出代码为 0

nearestPowerOfTwo方法

返回大于输入参数且最近的2的整数次幂的数方法测试如下,代码:

func BenchmarkApproach1(b *testing.B) {
    for i := 0; i < b.N; i++ {
       _ = int(math.Log2(float64(nearestPowerOfTwo(b.N))))
    }
}

func BenchmarkApproach2(b *testing.B) {
    for i := 0; i < b.N; i++ {
       _ = math.Ceil(math.Log2(float64(b.N)))
    }
}

输入打印如下:

$ go test -benchmem -bench .
goos: windows
goarch: amd64
pkg: mytest/com/zhb/utils
cpu: 12th Gen Intel(R) Core(TM) i5-12600KF
BenchmarkApproach1-16           277866668                4.158 ns/op           0 B/op          0 allocs/op
BenchmarkApproach2-16           151868052                7.809 ns/op           0 B/op          0 allocs/op
PASS
ok      mytest/com/zhb/utils    4.316s

优化前后性能对比

优化前后性能对比,代码如下:

func BenchmarkApproach3(b *testing.B) {
	for i := 0; i < b.N; i++ {
		_ = testUtil.RandomChars(1 << 10)
	}
}

func BenchmarkApproach4(b *testing.B) {
	for i := 0; i < b.N; i++ {
		_ = strutil.RandomChars(1 << 10)
	}
}

func BenchmarkApproach5(b *testing.B) {
	for i := 0; i < b.N; i++ {
		_ = testUtil.RandomCharsV2(1 << 10)
	}
}

func BenchmarkApproach6(b *testing.B) {
	for i := 0; i < b.N; i++ {
		_ = strutil.RandomCharsV2(1 << 10)
	}
}

func BenchmarkApproach7(b *testing.B) {
	for i := 0; i < b.N; i++ {
		_ = testUtil.RandomCharsV3(1 << 10)
	}
}

func BenchmarkApproach8(b *testing.B) {
	for i := 0; i < b.N; i++ {
		_ = strutil.RandomCharsV3(1 << 10)
	}
}

输出打印如下:

$ go test -benchmem -bench .
goos: windows
goarch: amd64
pkg: mytest/com/zhb/utils
cpu: 12th Gen Intel(R) Core(TM) i5-12600KF
BenchmarkApproach3-16             288414              3954 ns/op            1024 B/op          1 allocs/op
BenchmarkApproach4-16             108159             11052 ns/op            7472 B/op          4 allocs/op
BenchmarkApproach5-16             136956              8588 ns/op            1024 B/op          1 allocs/op
BenchmarkApproach6-16             107840             11156 ns/op            7472 B/op          4 allocs/op
BenchmarkApproach7-16             749732              1783 ns/op            1024 B/op          1 allocs/op
BenchmarkApproach8-16             107077             11216 ns/op            7472 B/op          4 allocs/op
PASS
ok      mytest/com/zhb/utils    8.544s

优化前后准确性对比

优化前后准确性对比,代码如下:

func TestApproach1(t *testing.T) {
	println("Approach1-testUtil")
	for i := 0; i < 10; i++ {
		println(testUtil.RandomChars(32))
	}
	println("Approach1-strUtil")
	for i := 0; i < 10; i++ {
		println(strutil.RandomChars(32))
	}
}

func TestApproach2(t *testing.T) {
	println("Approach2-testUtil")
	for i := 0; i < 10; i++ {
		println(testUtil.RandomCharsV2(32))
	}
	println("Approach2-strUtil")
	for i := 0; i < 10; i++ {
		println(strutil.RandomCharsV2(32))
	}
}

func TestApproach3(t *testing.T) {
	println("Approach3-testUtil")
	for i := 0; i < 10; i++ {
		println(testUtil.RandomCharsV3(32))
	}
	println("Approach3-strUtil")
	for i := 0; i < 10; i++ {
		println(strutil.RandomCharsV3(32))
	}
}

输出打印如下:

$ go test -benchmem -bench .
Approach1-testUtil
qfradxxxugivfeqdndkmwablgblbpmrq
iawlwilkjsyfbfyibiesrgcvxcktihqx
uvlimlwfvheezhoajjmugufdnijfonrw
heotinzkjwydwefjxxjrlbwajstherqo
klzwlmbmoqnhesinxduvnwarcdztwfzo
qtxknpgwkaecthmkcgpylqkqhblnwghv
qrmkukeiigoogfnuglhnelhoodctnnor
ozwjggaoccrujwsydzurhppvutcotaok
ezymohbmmkgfioujstqddlumydtoktji
ucsisvhejomsefnkmmfjwwidyxmifycm
Approach1-strUtil
nwjhtxwrojjrpumddjfmkuxxksxpturm
nwjhtxwrojjrpumddjfmkuxxksxpturm
nwjhtxwrojjrpumddjfmkuxxksxpturm
cxtldieyfuevrlqbrhomdsyahfdfbhml
cxtldieyfuevrlqbrhomdsyahfdfbhml
cxtldieyfuevrlqbrhomdsyahfdfbhml
cxtldieyfuevrlqbrhomdsyahfdfbhml
cxtldieyfuevrlqbrhomdsyahfdfbhml
cxtldieyfuevrlqbrhomdsyahfdfbhml
cxtldieyfuevrlqbrhomdsyahfdfbhml
Approach2-testUtil
fut0tk6qyg6zas3w428bg9xo79a8apek
2xd7779ws7dn3kto63vfycwiva9kwhf2
c5oi8awgiuyza7cba8s4sjw0qmygciu9
8w9d2ng9gndb6o99ymbcfcakjehtauxk
c0zsh48oirvzvq8u0q6z5sxonmw4w89y
4so6b8fqlyhhiulqz4czfckn9mv5foxf
qzigv9vbk1byyew2k22n9on7qg0xtr7g
8bsnlqcy12qk6m2ls83xf6ro6x2m1tz1
9ielerjzg75ugjhq10lr0u8rwer6hwpf
3zcl0w0q0c10vqyicef2mpsx2dgwfvy3
Approach2-strUtil
yhjgeb38po4d5k1511bl6x5osxtx0vnj
yhjgeb38po4d5k1511bl6x5osxtx0vnj
4vlcpg5j75j0qrc2haocto40tfs30nah
4vlcpg5j75j0qrc2haocto40tfs30nah
4vlcpg5j75j0qrc2haocto40tfs30nah
4vlcpg5j75j0qrc2haocto40tfs30nah
4vlcpg5j75j0qrc2haocto40tfs30nah
4vlcpg5j75j0qrc2haocto40tfs30nah
4vlcpg5j75j0qrc2haocto40tfs30nah
4vlcpg5j75j0qrc2haocto40tfs30nah
Approach3-testUtil
gPcjM6IBQ9CsrMqcHNGlSGHJS9sG7jgG
8ZqiXVkryXPmxq0lIXw03gyKMVxz1u89
gk2qzEN1GNQ57vkBOy6jWQs3VhlhHCBQ
ZtpmUIfuhmNE6X9jrmZumFpvEl8hAmzh
oA5trh14GyS59O0spbdVrqFSKdaGmcg7
UhqZTGllUjA28AVpUmiajH61y0aNNmpT
rDwSgIQPJauBzzLO2Ka9el5MgoP4nNso
CEoqbiQfT8M1pEIB9QTYzR5r0LCpQCtn
2fNUKyRiq7Zl3f3bfIw16EKiyHSZDG3J
SpM0gUnE31p01r6Ixth8HXFyZnkLQneB
Approach3-strUtil
taNxbaWkYLwfFF50ko3mLtll1BX1gW2K
taNxbaWkYLwfFF50ko3mLtll1BX1gW2K
By4WjX8QiNPz10b38DIHcFn0KJQJsMrB
By4WjX8QiNPz10b38DIHcFn0KJQJsMrB
By4WjX8QiNPz10b38DIHcFn0KJQJsMrB
By4WjX8QiNPz10b38DIHcFn0KJQJsMrB
By4WjX8QiNPz10b38DIHcFn0KJQJsMrB
By4WjX8QiNPz10b38DIHcFn0KJQJsMrB
By4WjX8QiNPz10b38DIHcFn0KJQJsMrB
By4WjX8QiNPz10b38DIHcFn0KJQJsMrB
PASS
ok      mytest/com/zhb/utils    0.044s

优化后实际效果仍有待完整测试

@inhere inhere added the enhancement New feature or request label Jan 29, 2024
@inhere inhere merged commit 778a092 into gookit:master Jan 31, 2024
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants