Go语言黑魔法
今天我要教大家一些无用技能,也可以叫它奇技淫巧或者黑魔法。用得好可以提升性能,用得不好就会招来恶魔,嘿嘿。
黑魔法导论
为了让大家在学习了基础黑魔法之后能有所悟,在必要的时候能创造出本文传授之外的属于自己的魔法,这里需要先给大家打好基础。
学习Go语言黑魔法之前,需要先看清Go世界的本质,你才能获得像Neo一样的能力。
在Go语言中,Slice本质是什么呢?是一个reflect.SliceHeader结构体和这个结构体中Data字段所指向的内存。String本质是什么呢?是一个reflect.StringHeader结构体和这个结构体所指向的内存。
在Go语言中,指针的本质是什么呢?是unsafe.Pointer和uintptr。
当你清楚了它们的本质之后,你就可以随意的玩弄它们,嘿嘿嘿。
式 - 获得Slice和String的内存数据
让我小试身手,你有一个CGO接口要调用,需要你把一个字符串数据或者字节数组数据从Go这边传递到C那边,比如像这个:mysql/conn.go at master · funny/mysql · GitHub
查了各种教程和文档,它们都告诉你要用C.GoString或C.GoBytes来转换数据。
但是,当你调用这两个函数的时候,发生了什么事情呢?这时候Go复制了一份数据,然后再把新数据的地址传给C,因为Go不想冒任何风险。
你的C程序只是想一次性的用一下这些数据,也不得不做一次数据复制,这对于一个性能癖来说是多麽可怕的一个事实!
这时候我们就需要一个黑魔法,来做到不拷贝数据又能把指针地址传递给C。
// returns &s[0], which is not allowed in go
func stringPointer(s string) unsafe.Pointer {
p := (*reflect.StringHeader)(unsafe.Pointer(&s))
return unsafe.Pointer(p.Data)
}
// returns &b[0], which is not allowed in go
func bytePointer(b []byte) unsafe.Pointer {
p := (*reflect.SliceHeader)(unsafe.Pointer(&b))
return unsafe.Pointer(p.Data)
}
相关文章