go unsafe常见应用
目录
1.强制类型转换
2.string与[]byte的高效转换
3.高效动态替换
go 本身是类似java一样,底层运行虚拟机,整个程序处于托管状态(GC等),要想和底层打交道需要用到unsafe模块,unsafe也常用于性能提升和程序灵活处理场景,本文介绍unsafe常用的几个场景。
常见unsafe用法如下
1.强制类型转换
要求必须内存布局一致,如下
// 正确转换必须保证内存布局一致
func TestConvert(t *testing.T) {var num int = 2numf := *(*float64)(unsafe.Pointer(&num))t.Logf("Convert int %v to float64 %v", num, numf)type MyInt intnums := []int{1, 2, 3}mynums := *(*[]MyInt)(unsafe.Pointer(&nums))t.Logf("Convert int array %v to myint array %v", nums, mynums)
}
结果如下, float64和int布局不一致所有不能正确转换
unsafe_test.go:15: Convert int 2 to float64 1e-323
unsafe_test.go:20: Convert int array [1 2 3] to myint array [1 2 3]
2.string与[]byte的高效转换
go的默认实现中,go和byte的转换需要通过拷贝,性能较低,如下测试
func BenchmarkByteString1(b *testing.B) {str := "this is a string"var bs []byteb.ResetTimer()for i := 0; i < b.N; i++ {bs = []byte(str)str = string(bs)}b.StopTimer()
}
结果如下
cpu: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz
BenchmarkByteString1
BenchmarkByteString1-12 25468410 42.08 ns/op
PASS
实际上,如下,因为string []byte底层结构很像,
// []byte其实就是byte类型的切片,对应的底层结构体定义如下(在runtime/slice.go文件中)
type slice struct {array unsafe.Pointerlen intcap int
}// string对应的底层结构体定义如下(在runtime/string.go文件中)
type stringStruct struct {str unsafe.Pointerlen int
}
因此,可以如下直接转换
// string转ytes
func Str2sbyte(s string) (b []byte) {*(*string)(unsafe.Pointer(&b)) = s // 把s的地址付给b*(*int)(unsafe.Pointer(uintptr(unsafe.Pointer(&b)) + 2*unsafe.Sizeof(&b))) = len(s) // 修改容量为长度return
}// []byte转string
func Sbyte2str(b []byte) string {return *(*string)(unsafe.Pointer(&b))
}func BenchmarkByteString2(b *testing.B) {str := "this is a string"var bs []byteb.ResetTimer()for i := 0; i < b.N; i++ {bs = Str2sbyte(str)str = Sbyte2str(bs)}b.StopTimer()
}
结果如下,大大提升
cpu: Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz
BenchmarkByteString2
BenchmarkByteString2-12 1000000000 0.3190 ns/op
PASS
实际上,go本身的实现也用到这个技巧,参考runtime/string.go
中slicebytetostringtmp
和stringtoslicebytetmp
两个函数 ,如下
func slicebytetostringtmp(b []byte) string {// Return a "string" referring to the actual []byte bytes.// This is only for use by internal compiler optimizations// that know that the string form will be discarded before// the calling goroutine could possibly modify the original// slice or synchronize with another goroutine.// First such case is a m[string(k)] lookup where// m is a string-keyed map and k is a []byte.// Second such case is "<"+string(b)+">" concatenation where b is []byte.// Third such case is string(b)=="foo" comparison where b is []byte.if raceenabled && len(b) > 0 {racereadrangepc(unsafe.Pointer(&b[0]),uintptr(len(b)),getcallerpc(unsafe.Pointer(&b)),funcPC(slicebytetostringtmp))}return *(*string)(unsafe.Pointer(&b))
}func stringtoslicebytetmp(s string) []byte {// Return a slice referring to the actual string bytes.// This is only for use by internal compiler optimizations// that know that the slice won't be mutated.// The only such case today is:// for i, c := range []byte(str)str := (*stringStruct)(unsafe.Pointer(&s))ret := slice{array: unsafe.Pointer(str.str), len: str.len, cap: str.len}return *(*[]byte)(unsafe.Pointer(&ret))
}
引用文章Go语言中[]byte和string类型相互转换时的性能分析和优化,描述如下
stringtoslicebytetmp
调用的前提是保证返回的[]byte之后不会被修改,只用于编译器内部优化,目前唯一的场景是在for loop中将string转换成[]byte做遍历操作时,比如for i, c := range []byte(str)
slicebytetostringtmp
调用的前提其实也是类似,保证返回的string在生命周期结束之前,[]byte不会被修改,也是只用于编译器内部优化,目前有三种场景:
- 假设有一个key为string的map遍历m,你想使用[]byte类型的变量k做查找操作,比如
m[string(k)]
- 做字符串拼接操作时,比如
<"+string(b)+">
,其中b是[]byte类型- []byte类型和常量字符串做比较操作,比如
string(b)=="foo"
3.高效动态替换
一个典型的场景是,一块共享的buffer,很多程序在同时读写,如何高性能的处理共享竞争问题?一个可行的方案是,写入时先写一个copy,然后原子替换老的内容,指针保持不变,如下
// 原子替换内存地址
func TestBuffer(t *testing.T) {var buffer unsafe.Pointervar wg sync.WaitGroupvar writeFn = func(index int) {b := make([]int, 0)b = append(b, index)b = append(b, index)b = append(b, index)atomic.StorePointer(&buffer, unsafe.Pointer(&b))}var readFn = func() {b := atomic.LoadPointer(&buffer)data := *(*[]int)(b)t.Log(b, data)}// 初始化writeFn(0)// 写入for i := 0; i < 10; i++ {wg.Add(1)go func(index int) {writeFn(i)time.Sleep(time.Millisecond * 100)wg.Done()}(i)}// 读取for i := 0; i < 3; i++ {wg.Add(1)go func() {readFn()time.Sleep(time.Millisecond * 100)wg.Done()}()}wg.Wait()
}
原创,转载请注明来自
- 博客https://blog.csdn.net/wenzhou1219
- 个人网站http://jimwen.net/
go unsafe常见应用相关推荐
- 网络常见攻击(知识点总结)
病毒,蠕虫,木马三者之间的区别 病毒,木马,蠕虫统称为电脑病毒.病毒(包含蠕虫)的共同特征是自我复制.传播.破坏电脑文件,对电脑造成数据上不可逆转的损坏.而木马独有特征是伪装成正常应用骗取用户信任而入 ...
- C#图片处理常见方法性能比较
在.NET编程中,由于GDI+的出现,使得对于图像的处理功能大大增强.在文通过一个简单黑白处理实例介绍在.NET中常见的图片处理方法和原理并比较各种方法的性能. 黑白处理原理:彩色图像处理成黑白效果通 ...
- Unsafe工具类的一些实用技巧,通往JVM底层的钥匙
欢迎关注方志朋的博客,回复"666"获面试宝典 前言 记得初学 Java 那会,刚学完语法基础,就接触到了反射这个 Java 提供的特性,尽管在现在看来,这是非常基础的知识点,但那 ...
- 聊聊Unsafe的一些使用技巧
记得初学 Java 那会,刚学完语法基础,就接触到了反射这个 Java 提供的特性,尽管在现在看来,这是非常基础的知识点,但那时候无疑是兴奋的,瞬间觉得自己脱离了"Java 初学者" ...
- Android项目:proguard混淆之常见开源项目混淆配置
1.Gson混淆 ## ---------------------------------- ## ########## Gson混淆 ########## ## ------------------ ...
- 转 常见hash算法的原理
散列表,它是基于快速存取的角度设计的,也是一种典型的"空间换时间"的做法.顾名思义,该数据结构可以理解为一个线性表,但是其中的元素不是紧密排列的,而是可能存在空隙. 散列表(Has ...
- Microsoft .NET Compact Framework 开发常见问题解答
这个 FAQ 有部分是通过编辑公共 .NET Compact Framework 新闻组 (microsoft.public.dotnet.framework.compactframework) 贴出 ...
- java 中random类使用_Java中的天使和魔鬼:Unsafe类
我们在看ConcurrentHashMap源码时经常看到Unsafe类的使用,今天我们来了解下Unsafe类. Java是一个安全的编程语言,它能最大程度的防止程序员犯一些低级的错误(大部分是和内存管 ...
- 聊聊高并发(十七)解析java.util.concurrent各个组件(一) 了解sun.misc.Unsafe类
了解了并发编程中锁的基本原理之后,接下来看看Java是如何利用这些原理来实现各种锁,原子变量,同步组件的.在开始分析java.util.concurrent的源代码直接,首先要了解的就是sun.mis ...
最新文章
- sqlplus 汉字乱码问题的解决
- 自定义UICollectionView
- tp5,thinkphp5,隐藏index.php,隐藏入口文件
- 淘宝直播的电商互动之路
- sqlite随机读取N条记录
- 后台执行UNIX/Linux命令和脚本的五种方法
- linux实例大全学习笔记1
- 第1章 计算机系统漫游(深入理解计算机系统)
- pom添加mysql依赖tomcat崩溃_Spring Boot + Mybatis + Spring MVC环境配置(一) :Spring Boot初始化,依赖添加...
- acs880变频器选型手册_变频器是否需要加进线、出线电抗器?
- 支持一切积极向上的自发行为
- sql选择性插入_SQL插入选择
- Ubuntu18.04安装英伟达显卡驱动
- c8500刷机 转帖
- 惠普服务器u盘启动找不到硬盘,U盘启动找不到硬盘怎么回事?
- A-B(字符串问题)
- 关于搭建简易广域网私人通信程序(python)一步到位!
- Tensorflow-Gpu安装 基于gtx1060
- 荣耀magic5和vivox90参数对比 荣耀magic5和vivox90哪个好
- 跨职能流程图_领导跨职能团队的6个关键技巧
热门文章
- ChatGPT与知识图谱对比
- windows autoconf、automake编译 fdk-aac2.0.2(msvc)
- 计算机文化宣传,计算机文化节活动宣传总策划书(doc 42页)
- ASH、AWR、ADDM区别联系
- 11.02 长者题解
- resnet网络特征提取过程可视化
- java printwriter乱码_PrintWriter输出中文乱码分析与解决方案
- Java毕设项目线上甜品店售卖系统(java+VUE+Mybatis+Maven+Mysql)
- hadoop基础选择题
- 游戏行业工资怎么样? 游戏建模这个工作前景怎么样