目录

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.goslicebytetostringtmpstringtoslicebytetmp两个函数 ,如下

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不会被修改,也是只用于编译器内部优化,目前有三种场景:

  1. 假设有一个key为string的map遍历m,你想使用[]byte类型的变量k做查找操作,比如 m[string(k)]
  2. 做字符串拼接操作时,比如 <"+string(b)+">,其中b是[]byte类型
  3. []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常见应用相关推荐

  1. 网络常见攻击(知识点总结)

    病毒,蠕虫,木马三者之间的区别 病毒,木马,蠕虫统称为电脑病毒.病毒(包含蠕虫)的共同特征是自我复制.传播.破坏电脑文件,对电脑造成数据上不可逆转的损坏.而木马独有特征是伪装成正常应用骗取用户信任而入 ...

  2. C#图片处理常见方法性能比较

    在.NET编程中,由于GDI+的出现,使得对于图像的处理功能大大增强.在文通过一个简单黑白处理实例介绍在.NET中常见的图片处理方法和原理并比较各种方法的性能. 黑白处理原理:彩色图像处理成黑白效果通 ...

  3. Unsafe工具类的一些实用技巧,通往JVM底层的钥匙

    欢迎关注方志朋的博客,回复"666"获面试宝典 前言 记得初学 Java 那会,刚学完语法基础,就接触到了反射这个 Java 提供的特性,尽管在现在看来,这是非常基础的知识点,但那 ...

  4. 聊聊Unsafe的一些使用技巧

    记得初学 Java 那会,刚学完语法基础,就接触到了反射这个 Java 提供的特性,尽管在现在看来,这是非常基础的知识点,但那时候无疑是兴奋的,瞬间觉得自己脱离了"Java 初学者" ...

  5. Android项目:proguard混淆之常见开源项目混淆配置

    1.Gson混淆 ## ---------------------------------- ## ########## Gson混淆 ########## ## ------------------ ...

  6. 转 常见hash算法的原理

    散列表,它是基于快速存取的角度设计的,也是一种典型的"空间换时间"的做法.顾名思义,该数据结构可以理解为一个线性表,但是其中的元素不是紧密排列的,而是可能存在空隙. 散列表(Has ...

  7. Microsoft .NET Compact Framework 开发常见问题解答

    这个 FAQ 有部分是通过编辑公共 .NET Compact Framework 新闻组 (microsoft.public.dotnet.framework.compactframework) 贴出 ...

  8. java 中random类使用_Java中的天使和魔鬼:Unsafe类

    我们在看ConcurrentHashMap源码时经常看到Unsafe类的使用,今天我们来了解下Unsafe类. Java是一个安全的编程语言,它能最大程度的防止程序员犯一些低级的错误(大部分是和内存管 ...

  9. 聊聊高并发(十七)解析java.util.concurrent各个组件(一) 了解sun.misc.Unsafe类

    了解了并发编程中锁的基本原理之后,接下来看看Java是如何利用这些原理来实现各种锁,原子变量,同步组件的.在开始分析java.util.concurrent的源代码直接,首先要了解的就是sun.mis ...

最新文章

  1. sqlplus 汉字乱码问题的解决
  2. 自定义UICollectionView
  3. tp5,thinkphp5,隐藏index.php,隐藏入口文件
  4. 淘宝直播的电商互动之路
  5. sqlite随机读取N条记录
  6. 后台执行UNIX/Linux命令和脚本的五种方法
  7. linux实例大全学习笔记1
  8. 第1章 计算机系统漫游(深入理解计算机系统)
  9. pom添加mysql依赖tomcat崩溃_Spring Boot + Mybatis + Spring MVC环境配置(一) :Spring Boot初始化,依赖添加...
  10. acs880变频器选型手册_变频器是否需要加进线、出线电抗器?
  11. 支持一切积极向上的自发行为
  12. sql选择性插入_SQL插入选择
  13. Ubuntu18.04安装英伟达显卡驱动
  14. c8500刷机 转帖
  15. 惠普服务器u盘启动找不到硬盘,U盘启动找不到硬盘怎么回事?
  16. A-B(字符串问题)
  17. 关于搭建简易广域网私人通信程序(python)一步到位!
  18. Tensorflow-Gpu安装 基于gtx1060
  19. 荣耀magic5和vivox90参数对比 荣耀magic5和vivox90哪个好
  20. 跨职能流程图_领导跨职能团队的6个关键技巧

热门文章

  1. ChatGPT与知识图谱对比
  2. windows autoconf、automake编译 fdk-aac2.0.2(msvc)
  3. 计算机文化宣传,计算机文化节活动宣传总策划书(doc 42页)
  4. ASH、AWR、ADDM区别联系
  5. 11.02 长者题解
  6. resnet网络特征提取过程可视化
  7. java printwriter乱码_PrintWriter输出中文乱码分析与解决方案
  8. Java毕设项目线上甜品店售卖系统(java+VUE+Mybatis+Maven+Mysql)
  9. hadoop基础选择题
  10. 游戏行业工资怎么样? 游戏建模这个工作前景怎么样