Commit c84d02bf authored by AlexStocks's avatar AlexStocks

Add: benchmark

parent 1d1f3cc8
...@@ -3,8 +3,9 @@ ...@@ -3,8 +3,9 @@
// governed by Apache License 2.0. // governed by Apache License 2.0.
// http://blog.csdn.net/siddontang/article/details/23541587 // http://blog.csdn.net/siddontang/article/details/23541587
// reflect.StringHeader和reflect.SliceHeader的结构体只相差末尾一个字段(cap) // the difference btw reflect.StringHeader and reflect.SliceHeader is that there is a 'cap' in reflect.SliceHeader.
// vitess代码,一种很hack的做法,string和slice的转换只需要拷贝底层的指针,而不是内存拷贝。 //
// The following codes is from a vitness project.
package gxstrings package gxstrings
import ( import (
...@@ -12,6 +13,8 @@ import ( ...@@ -12,6 +13,8 @@ import (
"unsafe" "unsafe"
) )
// String converts slice to a string object just by convert its pointer type
// on the same memory heap without copying.
func String(b []byte) (s string) { func String(b []byte) (s string) {
pbytes := (*reflect.SliceHeader)(unsafe.Pointer(&b)) pbytes := (*reflect.SliceHeader)(unsafe.Pointer(&b))
pstring := (*reflect.StringHeader)(unsafe.Pointer(&s)) pstring := (*reflect.StringHeader)(unsafe.Pointer(&s))
...@@ -20,6 +23,8 @@ func String(b []byte) (s string) { ...@@ -20,6 +23,8 @@ func String(b []byte) (s string) {
return return
} }
// String converts string to a slice object just by convert its pointer type
// on the same memory heap without copying.
func Slice(s string) (b []byte) { func Slice(s string) (b []byte) {
pbytes := (*reflect.SliceHeader)(unsafe.Pointer(&b)) pbytes := (*reflect.SliceHeader)(unsafe.Pointer(&b))
pstring := (*reflect.StringHeader)(unsafe.Pointer(&s)) pstring := (*reflect.StringHeader)(unsafe.Pointer(&s))
...@@ -40,4 +45,3 @@ func BytePointer(b []byte) unsafe.Pointer { ...@@ -40,4 +45,3 @@ func BytePointer(b []byte) unsafe.Pointer {
p := (*reflect.SliceHeader)(unsafe.Pointer(&b)) p := (*reflect.SliceHeader)(unsafe.Pointer(&b))
return unsafe.Pointer(p.Data) return unsafe.Pointer(p.Data)
} }
package gxstrings package gxstrings
import ( import (
"reflect"
"testing" "testing"
) )
// go test -v slice_test.go slice.go // go test -v slice_test.go slice.go
// slice转string之后,如果slice的值有变化,string也会跟着改变
func TestString(t *testing.T) { func TestString(t *testing.T) {
b := []byte("hello world") b := []byte("hello world")
// After converting slice to string, the string value will change
// when the slice got new value.
a := String(b) a := String(b)
b[0] = 'a' b[0] = 'a'
println(a) //output aello world if !reflect.DeepEqual("aello world", a) {
t.Errorf("a:%+v != `aello world`", a)
}
} }
func TestSlice(t *testing.T) { // BenchmarkString0-8 2000000000 0.27 ns/op
// 编译器会把 "hello, world" 这个字符串常量的字节数组分配在没有写权限的 memory segment func BenchmarkString0(b *testing.B) {
a := "hello world" b.StartTimer()
b := Slice(a) for i := 0; i < 100000000; i++ {
bs := []byte("hello world")
// !!! 上面这个崩溃在defer里面是recover不回来的,真的就崩溃了,原因可能就跟c的非法内存访问一样,os不跟你玩了 _ = string(bs)
// b[0] = 'a' //这里就等着崩溃吧 bs[0] = 'a'
}
b.StopTimer()
bs := []byte("hello world")
a := string(bs)
bs[0] = 'a'
if reflect.DeepEqual("aello world", a) {
b.Errorf("a:%+v != `aello world`", a)
}
}
//但是可以这样,因为go又重新给b分配了内存 // BenchmarkString-8 1 1722255064 ns/op
b = append(b, "hello world"...) func BenchmarkString(b *testing.B) {
println(String(b)) // output: hello worldhello world b.StartTimer()
for i := 0; i < 100000000; i++ {
bs := []byte("hello world")
_ = String(bs)
bs[0] = 'a'
}
b.StopTimer()
bs := []byte("hello world")
a := String(bs)
bs[0] = 'a'
if !reflect.DeepEqual("aello world", a) {
b.Errorf("a:%+v != `aello world`", a)
}
} }
func TestSlice2(t *testing.T) { func TestSlice(t *testing.T) {
// 你可以动态生成一个字符串,使其分配在可写的区域,比如 gc heap,那么就不会崩溃了。
a := string([]byte("hello world")) a := string([]byte("hello world"))
b := Slice(a) b := Slice(a)
b = append(b, "hello world"...) b = append(b, "hello world"...)
println(String(b)) // output: hello worldhello world println(String(b))
if !reflect.DeepEqual([]byte("hello worldhello world"), b) {
t.Errorf("a:%+v != `hello worldhello world`", string(b))
}
} }
// BenchmarkSlice0-8 1 1187713598 ns/op
func BenchmarkSlice0(b *testing.B) {
for i := 0; i < 100000000; i++ {
a := string([]byte("hello world"))
bs := ([]byte)(a)
_ = append(bs, "hello world"...)
}
}
// BenchmarkSlice-8 1 4895001383 ns/op
func BenchmarkSlice(b *testing.B) {
for i := 0; i < 100000000; i++ {
a := string([]byte("hello world"))
bs := Slice(a)
_ = append(bs, "hello world"...)
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment