文档章节

Go性能优化技巧 1/10

雨痕学堂
 雨痕学堂
发布于 2016/04/26 00:12
字数 545
阅读 315
收藏 11

字符串(string)作为一种不可变类型,在与字节数组(slice, [ ]byte)转换时需付出 “沉重” 代价,根本原因是对底层字节数组的复制。这种代价会在以万为单位的高并发压力下迅速放大,所以对它的优化常变成 “必须” 行为。


首先,须了解 string 和 [ ]byte 数据结构,并确认默认方式的复制行为。

package main

import (
	"fmt"
)

func main() {
	s := "hello, world!"
	b := []byte(s)
	fmt.Println(s, b)
}


动态演示: https://asciinema.org/a/6up6gvgqo0v9zkjpusvyucg8g

从 GDB 输出结果可看出,转换后 [ ]byte 底层数组与原 string 内部指针并不相同,以此可确定数据被复制。那么,如不修改数据,仅转换类型,是否可避开复制,从而提升性能?


从 ptype 输出的结构来看,string 可看做 [2]uintptr,而 [ ]byte 则是 [3]uintptr,这便于我们编写代码,无需额外定义结构类型。如此,str2bytes 只需构建 [3]uintptr{ptr, len, len},而 bytes2str 更简单,直接转换指针类型,忽略掉 cap 即可。

package main

import (
	"fmt"
	"strings"
	"unsafe"
)

func str2bytes(s string) []byte {
	x := (*[2]uintptr)(unsafe.Pointer(&s))
	h := [3]uintptr{x[0], x[1], x[1]}
	return *(*[]byte)(unsafe.Pointer(&h))
}

func bytes2str(b []byte) string {
	return *(*string)(unsafe.Pointer(&b))
}

func main() {
	s := strings.Repeat("abc", 3)
	b := str2bytes(s)
	s2 := bytes2str(b)
	fmt.Println(b, s2)
}


用 unsafe 完成指针类型转换,所以得自行为底层数组生命周期做出保证。好在这两个函数都很简单,编译器会完成内联处理,并未发生逃逸行为。

对比一下优化前后的性能差异。

package main

import (
	"strings"
	"testing"
)

var s = strings.Repeat("a", 1024)

func test() {
	b := []byte(s)
	_ = string(b)
}

func test2() {
	b := str2bytes(s)
	_ = bytes2str(b)
}

func BenchmarkTest(b *testing.B) {
	for i := 0; i < b.N; i++ {
		test()
	}
}

func BenchmarkTestBlock(b *testing.B) {
	for i := 0; i < b.N; i++ {
		test2()
	}
}


性能提升明显,最关键的是 zero-garbage。


最新动态,请扫码关注

© 著作权归作者所有

雨痕学堂
粉丝 19
博文 11
码字总数 5234
作品 0
朝阳
私信 提问
PHP性能优化的小技巧

今天我们来分享10条PHP性能优化的小技巧: (1)循环内部不要声明变量,尤其是对象这样的变量 (2)foreach效率更高,尽量用foreach代替while和for循环 (3)在多重嵌套循环中,如有可能,应当将最...

京牛教育科技
2016/08/26
40
0
思途|Java就业培训之优化Java性能的10个技巧

很多人都理所当然的以为性能优化是一件复杂且深奥的事情,需要具备丰富经验和知识前提;可实际上,虽然这事儿不算简单,但也并不代表你不了解这些知识就不能做任何事情。下面,我们会分享给大...

思途科技在线
2017/12/15
0
0
Unity优化百科(UWA 博客目录)

原文链接:https://blog.uwa4d.com/archives/Index.html Hello, 各位Unity开发者,无论您是正用着UWA的工具、还是阅读着UWA的相关技术文章亦或是在UWA博客中寻找一个问题的解答,我们都倍感荣...

UWA4D
2017/10/26
0
0
Padded优化LinkedTransferQue并发性能是错误方向

在Grizzly中,自带了LinkedTransferQueue,和JDK 7自带的LinkedTransferQueue有所不同,不同之处就是使用PaddedAtomicReference来提升并发性能,其实这是一种错误的编码技巧,没有意义! At...

wenshao
2012/11/20
4K
22
年薪:8-10万学历不限招高级工程师

北京神州立诚科技有限公司(广州公司) Novell中国区盒装产品总代理 EnterpriseDB大中华区总代理(包括港澳台) 公司网址:http://www.focus-soft.com 工作职位:高级工程师 工作范围: 负责软件...

JavaGG
2012/04/19
3.1K
14

没有更多内容

加载失败,请刷新页面

加载更多

OSChina 周二乱弹 —— 他只能用这个办法劝你注意身体了

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @-冰冰棒- :#今日歌曲推荐# Kodaline《High Hopes》 《High Hopes》- Kodaline 手机党少年们想听歌,请使劲儿戳(这里) @xiaoshiyue :仙女...

小小编辑
21分钟前
610
13
Spring Boot Actuator 整合 Prometheus

简介 Spring Boot 自带监控功能 Actuator,可以帮助实现对程序内部运行情况监控,比如监控状况、Bean加载情况、环境变量、日志信息、线程信息等。这一节结合 Prometheus 、Grafana 来更加直观...

程序员果果
30分钟前
8
0
Linux文件查找命令详解

对于文件查找,我们最好用的还是属于find命令了,在说find命令之前,先把另外几个查找命令介绍一下。 目录 0x01 查询命令介绍 0x02 find命令介绍 0x01 查询命令介绍 在介绍之前,首先先了解一...

无心的梦呓
30分钟前
5
0
快速掌握的测试用例优先级划分方法

怎么样的设计才能算测试用例 引自:IEEE Standard 610 (1990): A set of test inputs, execution conditions, and expected results developed for a particular objective, such as to exe......

测者陈磊
33分钟前
4
0
[mycat]Attribute value "roadNodeId,version" of type NMTOKEN must be a name token

不能逗号配两个字段的主键 primaryKey="roadNodeId,version" Caused by: io.mycat.config.util.ConfigException: org.xml.sax.SAXParseException; lineNumber: 7; columnNumber: 105; Attrib......

Danni3
39分钟前
6
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部