分享
  1. 首页
  2. 文章

Golang unsafe包使用笔记

tommwq · · 2339 次点击 · · 开始浏览
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

Golang unsafe包使用笔记

unsafe包简介

unsafe包提供了访问底层内存的方法。是用unsafe函数可以提高访问对象的速度。

应用场景

通常用于对大数组的遍历。

访问数组

package main
import (
 "fmt"
 "unsafe"
)
func main() {
 array := []int{1, 2, 3}
 base := uintptr(unsafe.Pointer(&array[0]))
 size := unsafe.Sizeof(array[0])
 ptr := unsafe.Pointer(base + 2*size)
 element := *(*int)(ptr)
 fmt.Println(element, array[2])
}

访问结构体

package main
import (
 "fmt"
 "unsafe"
)
type Foo struct {
 A int
 B int
}
func main() {
 foo := &Foo{1, 2}
 fmt.Println(foo)
 base := uintptr(unsafe.Pointer(foo))
 offset := unsafe.Offsetof(foo.A)
 ptr := unsafe.Pointer(base + offset)
 *(*int)(ptr) = 3
 fmt.Println(foo)
}

类型转换

package main
import (
 "fmt"
 "unsafe"
)
func main() {
 var f float64 = 0.0
 var x uint64 = *(*uint64)(unsafe.Pointer(&f))
 fmt.Println(f, x)
}

注意事项

  1. unsafe可能引起兼容性问题。

性能测试

代码:

func sum(arr []int) int {
 sum := 0
 for _, x := range arr {
 sum += x
 }
 return sum
}
func unsafeSum(arr []int) int {
 ptr := unsafe.Pointer(&arr[0])
 count := len(arr)
 step := unsafe.Sizeof(arr[0])
 sum := 0
 for i := 0; i < count; i++ {
 sum += *(*int)(ptr)
 ptr = unsafe.Pointer(uintptr(ptr) + step)
 }
 return sum
}
func unsafeSum2(arr []int) int {
 base := unsafe.Pointer(&arr[0])
 count := len(arr)
 step := unsafe.Sizeof(arr[0])
 sum := 0
 for i := 0; i < count; i++ {
 ptr := unsafe.Pointer(uintptr(base) + uintptr(i)*step)
 sum += *(*int)(ptr)
 }
 return sum
}
func unsafeSum3(arr []int) int {
 beg := unsafe.Pointer(&arr[0])
 size := unsafe.Sizeof(arr[0])
 end := unsafe.Pointer(uintptr(beg) + uintptr(len(arr))*size)
 ptr := beg
 sum := 0
 for ptr != end {
 sum += *(*int)(ptr)
 ptr = unsafe.Pointer(uintptr(ptr) + size)
 }
 return sum
}

测试代码:

package main
import (
 "testing"
)
var (
 array = []int{
 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
 }
)
func BenchmarkUnsafeSum(b *testing.B) {
 for i := 0; i < b.N; i++ {
 unsafeSum(array)
 }
}
func BenchmarkSum(b *testing.B) {
 for i := 0; i < b.N; i++ {
 sum(array)
 }
}
func TestUnsafeSum(t *testing.T) {
 if result := unsafeSum(array); result != 550 {
 t.Fatal("expect %v get %v", 550, result)
 }
}
func TestUnsafeSum2(t *testing.T) {
 if result := unsafeSum2(array); result != 550 {
 t.Fatal("expect %v get %v", 550, result)
 }
}
func BenchmarkUnsafeSum2(b *testing.B) {
 for i := 0; i < b.N; i++ {
 unsafeSum2(array)
 }
}
func TestUnsafeSum3(t *testing.T) {
 if result := unsafeSum3(array); result != 550 {
 t.Fatal("expect %v get %v", 550, result)
 }
}
func BenchmarkUnsafeSum3(b *testing.B) {
 for i := 0; i < b.N; i++ {
 unsafeSum3(array)
 }
}

结果:

BenchmarkUnsafeSum-2 20000000 94.0 ns/op
BenchmarkSum-2 10000000 129 ns/op
BenchmarkUnsafeSum2-2 10000000 126 ns/op
BenchmarkUnsafeSum3-2 20000000 84.0 ns/op
PASS
ok tq/lab/Unsafe 6.926s

参考资料

  1. http://golang.org/pkg/unsafe

修订记录

  1. 2017年06月15日 建立文档。

有疑问加站长微信联系(非本文作者)

本文来自:开源中国博客

感谢作者:tommwq

查看原文:Golang unsafe包使用笔记

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

关注微信
2339 次点击
暂无回复
添加一条新回复 (您需要 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传

用户登录

没有账号?注册
(追記) (追記ここまで)

今日阅读排行

    加载中
(追記) (追記ここまで)

一周阅读排行

    加载中

关注我

  • 扫码关注领全套学习资料 关注微信公众号
  • 加入 QQ 群:
    • 192706294(已满)
    • 731990104(已满)
    • 798786647(已满)
    • 729884609(已满)
    • 977810755(已满)
    • 815126783(已满)
    • 812540095(已满)
    • 1006366459(已满)
    • 692541889

  • 关注微信公众号
  • 加入微信群:liuxiaoyan-s,备注入群
  • 也欢迎加入知识星球 Go粉丝们(免费)

给该专栏投稿 写篇新文章

每篇文章有总共有 5 次投稿机会

收入到我管理的专栏 新建专栏