gui*_*apc 2 string utf-8 go rune
当我有一个字符串"hogemogehogemogehogemoge世界世界世界"哪个代码更好,以避免内存分配得到最后的符文?
关于获取Golang String的最后X个字符有类似的问题.
如果我只是想获得最后一个符文,我想确定哪个是首选的,没有任何额外的操作.
package main
import (
"fmt"
"unicode/utf8"
)
func main() {
// which is more better for memory allocation?
s := "hogemogehogemogehogemoge??????a"
getLastRune(s, 3)
getLastRune2(s, 3)
}
func getLastRune(s string, c int) {
// DecodeLastRuneInString
j := len(s)
for i := 0; i < c && j > 0; i++ {
_, size := utf8.DecodeLastRuneInString(s[:j])
j -= size
}
lastByRune := s[j:]
fmt.Println(lastByRune)
}
func getLastRune2(s string, c int) {
// string -> []rune
r := []rune(s)
lastByRune := string(r[len(r)-c:])
fmt.Println(lastByRune)
}
Run Code Online (Sandbox Code Playgroud)
世界一
世界一
每当性能和分配成为问题时,您应该运行基准测试.
首先让我们修改你的函数不打印,而是返回结果:
func getLastRune(s string, c int) string {
j := len(s)
for i := 0; i < c && j > 0; i++ {
_, size := utf8.DecodeLastRuneInString(s[:j])
j -= size
}
return s[j:]
}
func getLastRune2(s string, c int) string {
r := []rune(s)
if c > len(r) {
c = len(r)
}
return string(r[len(r)-c:])
}
Run Code Online (Sandbox Code Playgroud)
基准功能:
var s = "hogemogehogemogehogemoge??????a"
func BenchmarkGetLastRune(b *testing.B) {
for i := 0; i < b.N; i++ {
getLastRune(s, 3)
}
}
func BenchmarkGetLastRune2(b *testing.B) {
for i := 0; i < b.N; i++ {
getLastRune2(s, 3)
}
}
Run Code Online (Sandbox Code Playgroud)
运行它们:
go test -bench . -benchmem
Run Code Online (Sandbox Code Playgroud)
结果:
BenchmarkGetLastRune-4 30000000 36.9 ns/op 0 B/op 0 allocs/op
BenchmarkGetLastRune2-4 10000000 165 ns/op 0 B/op 0 allocs/op
Run Code Online (Sandbox Code Playgroud)
getLastRune()速度提高了4倍多.它们都没有进行任何分配,但这是由于编译器优化(转换string为[]rune和返回通常需要分配).
如果我们运行禁用优化的基准测试:
go test -gcflags '-N -l' -bench . -benchmem
Run Code Online (Sandbox Code Playgroud)
结果:
BenchmarkGetLastRune-4 30000000 46.2 ns/op 0 B/op 0 allocs/op
BenchmarkGetLastRune2-4 10000000 197 ns/op 16 B/op 1 allocs/op
Run Code Online (Sandbox Code Playgroud)
编译器优化与否,getLastRune()是明显的赢家.