string - 获取 Golang 字符串的最后一个 X 字符哪个更好?
问题描述
当我有字符串“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)
}
世界a
世界a
解决方案
每当性能和分配成为问题时,您都应该运行基准测试。
首先让我们修改您的函数以不打印而是返回结果:
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:])
}
和基准功能:
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)
}
}
运行它们:
go test -bench . -benchmem
结果:
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
getLastRune()
快了4 倍以上。他们都没有进行任何分配,但这是由于编译器优化(将 a 转换string
为[]rune
和返回通常需要分配)。
如果我们在禁用优化的情况下运行基准测试:
go test -gcflags '-N -l' -bench . -benchmem
结果:
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
编译器优化与否,getLastRune()
显然是赢家。
推荐阅读
- ruby-on-rails - Rails 和 Activerecord,更好的方法来统一几个对象来绘制比较表
- android - 带有 androidx 的 Material OutlinedBox 提示
- reactjs - 反应:组件属性未正确存储我想要的数据(来自查询)
- vb.net - 如何隐藏 DataGridView 中的重复行?
- typescript - 如何将索引类型与交集类型结合起来
- tensorflow - TensorFlow2 中的 tf.nn.ctc_beam_search_decoder() 不支持 GPU 吗?
- ios - Swift:我可以让下拉菜单保持可点击状态吗
- git - 如何使用 git log 使用 parent #1 来生成补丁
- java - Java 方法重载 - 两个列表
- sql-server - 为什么字符串数据列的旋转与 row_number 一起使用?