├── labs30 ├── README.md └── labs30.go ├── labs11 ├── README.md └── labs11.go ├── labs21 ├── labs21.c ├── labs21.go ├── labs21_test.go └── README.md ├── labs14 ├── README.md ├── cgo_string.go └── cgo_copy.go ├── labs10 ├── README.md ├── inner.go ├── labs10_test.go ├── inner.c └── labs10.go ├── labs20 ├── labs20.h ├── labs20.c ├── labs20_test.go ├── README.md └── labs20.go ├── labs27 ├── labs27_test.go ├── labs27.go └── README.md ├── labs22 ├── mylib │ ├── mylib.go │ └── hack.sh ├── labs22_test.go └── README.md ├── labs28 ├── README.md └── labs28_test.go ├── labs12 ├── README.md ├── labs12_test.go └── labs12.go ├── labs26 ├── README.md └── labs26_test.go ├── labs18 ├── README.md ├── labs18_test.go └── labs18.go ├── labs02 ├── README.md └── labs02_test.go ├── labs16 ├── README.md └── labs16_test.go ├── labs24 ├── README.md ├── labs24_test.go └── labs24.go ├── labs23 ├── README.md ├── labs23_test.go └── labs23.go ├── labs25 ├── README.md └── labs25_test.go ├── labs01 ├── README.md └── labs01_test.go ├── labs04 ├── README.md └── labs04_test.go ├── labs17 ├── README.md └── labs17_test.go ├── labs19 ├── README.md ├── labs19_test.go └── normal.go ├── labs03 ├── README.md └── labs03_test.go ├── labs15 ├── labs15_test.go └── demo_db.go ├── labs06 ├── README.md └── labs06_test.go ├── labs09 ├── labs09_test.go └── README.md ├── labs31 ├── README.md └── labs31_test.go ├── labs13 ├── README.md ├── many_object1.go ├── many_object2.go ├── many_object5.go ├── many_object3.go ├── many_object4.go └── many_object6.go ├── labs07 ├── README.md ├── labs07.go └── labs07_test.go ├── labs08 ├── README.md ├── labs08.go └── labs08_test.go ├── README.md ├── labs29 ├── README.md └── labs29_test.go └── labs05 ├── README.md └── labs05_test.go /labs30/README.md: -------------------------------------------------------------------------------- 1 | 内存数据库事务demo -------------------------------------------------------------------------------- /labs11/README.md: -------------------------------------------------------------------------------- 1 | 测试json序列化支持的类型 -------------------------------------------------------------------------------- /labs21/labs21.c: -------------------------------------------------------------------------------- 1 | 2 | void ·cfunc() { 3 | 4 | } -------------------------------------------------------------------------------- /labs14/README.md: -------------------------------------------------------------------------------- 1 | 测试用cgo复制go的内存数据和还原数据。 2 | 3 | 运行: 4 | 5 | go run cgo_copy.go 6 | 7 | -------------------------------------------------------------------------------- /labs21/labs21.go: -------------------------------------------------------------------------------- 1 | package labs21 2 | 3 | func cfunc() 4 | 5 | func gofunc() { 6 | 7 | } 8 | -------------------------------------------------------------------------------- /labs10/README.md: -------------------------------------------------------------------------------- 1 | 尝试绕过gc扫描,实际用到项目里发现会导致在其他地方出现内存分配死锁的错误,所以不敢实际使用,并且经过测试发现mallocgc还是不能绕过gc扫描,反而C.malloc更简单有效。 -------------------------------------------------------------------------------- /labs20/labs20.h: -------------------------------------------------------------------------------- 1 | 2 | extern void go_func(); 3 | 4 | extern void go_call_c(); 5 | 6 | extern void c_call_go(int); 7 | -------------------------------------------------------------------------------- /labs10/inner.go: -------------------------------------------------------------------------------- 1 | package labs10 2 | 3 | import ( 4 | "unsafe" 5 | ) 6 | 7 | func xnew(size int) unsafe.Pointer 8 | 9 | func xfree(p unsafe.Pointer) 10 | -------------------------------------------------------------------------------- /labs27/labs27_test.go: -------------------------------------------------------------------------------- 1 | package labs27 2 | 3 | import "testing" 4 | 5 | func Benchmark_Goid(b *testing.B) { 6 | for i := 0; i < b.N; i++ { 7 | goid() 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /labs10/labs10_test.go: -------------------------------------------------------------------------------- 1 | package labs10 2 | 3 | import "testing" 4 | 5 | func Test_NewBigStruct(t *testing.T) { 6 | bs := NewBigStruct() 7 | 8 | FreeBigStruct(bs) 9 | } 10 | -------------------------------------------------------------------------------- /labs22/mylib/mylib.go: -------------------------------------------------------------------------------- 1 | package mylib 2 | 3 | /* 4 | void cfunc() { 5 | } 6 | */ 7 | import "C" 8 | 9 | func Call(n int) { 10 | for i := 0; i < n; i++ { 11 | C.cfunc() 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /labs20/labs20.c: -------------------------------------------------------------------------------- 1 | #include "labs20.h" 2 | 3 | void go_call_c() { 4 | 5 | } 6 | 7 | void c_call_go(int n) { 8 | int i; 9 | 10 | for (i = 0; i < n; i ++) { 11 | go_func(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /labs20/labs20_test.go: -------------------------------------------------------------------------------- 1 | package labs20 2 | 3 | import "testing" 4 | 5 | func Benchmark_Go_Call_C(b *testing.B) { 6 | do_go_call_c(b.N) 7 | } 8 | 9 | func Benchmark_C_Call_GO(b *testing.B) { 10 | do_c_call_go(b.N) 11 | } 12 | -------------------------------------------------------------------------------- /labs27/labs27.go: -------------------------------------------------------------------------------- 1 | package labs27 2 | 3 | import "bytes" 4 | import "runtime" 5 | 6 | func goid() string { 7 | buf := make([]byte, 15) 8 | buf = buf[:runtime.Stack(buf, false)] 9 | return string(bytes.Split(buf, []byte(" "))[1]) 10 | } 11 | -------------------------------------------------------------------------------- /labs22/labs22_test.go: -------------------------------------------------------------------------------- 1 | package labs22 2 | 3 | import "testing" 4 | 5 | import "labs22/mylib" 6 | 7 | func Test_Go_Call_C(t *testing.T) { 8 | mylib.Call(1) 9 | } 10 | 11 | func Benchmark_Go_Call_C(b *testing.B) { 12 | mylib.Call(b.N) 13 | } 14 | -------------------------------------------------------------------------------- /labs27/README.md: -------------------------------------------------------------------------------- 1 | 测试不修改runtime代码的情况下获取goid的效率。 2 | 3 | 测试结果: 4 | 5 | ``` 6 | $ go test -bench="." 7 | testing: warning: no tests to run 8 | PASS 9 | Benchmark_Goid 500000 3612 ns/op 10 | ok github.com/idada/go-labs/labs27 1.848s 11 | ``` -------------------------------------------------------------------------------- /labs28/README.md: -------------------------------------------------------------------------------- 1 | 测试`[]byte`转`string`的效率。 2 | 3 | 测试结果: 4 | 5 | ``` 6 | $ go test -bench="." 7 | PASS 8 | Benchmark_Normal 20000000 63.4 ns/op 9 | Benchmark_ByteString 2000000000 0.55 ns/op 10 | ok github.com/idada/go-labs/labs28 2.486s 11 | ``` 12 | -------------------------------------------------------------------------------- /labs20/README.md: -------------------------------------------------------------------------------- 1 | 测试Go调用C和C调用Go的效率差异。 2 | 3 | 测试结果: 4 | 5 | ``` 6 | > go test labs20 -bench=".*" 7 | testing: warning: no tests to run 8 | PASS 9 | Benchmark_Go_Call_C 50000000 55.6 ns/op 10 | Benchmark_C_Call_GO 5000000 434 ns/op 11 | ok labs20 5.473s 12 | ``` -------------------------------------------------------------------------------- /labs10/inner.c: -------------------------------------------------------------------------------- 1 | #include "runtime.h" 2 | 3 | void* runtime·mallocgc(uintptr size, uint32 flag, int32 dogc, int32 zeroed); 4 | 5 | void ·xfree(void *p){ 6 | runtime·free(*(&p)); 7 | } 8 | 9 | void ·xnew(uintptr size,void *p){ 10 | *(&p) = runtime·mallocgc(size, 1<<2, 0, 0); 11 | } 12 | -------------------------------------------------------------------------------- /labs21/labs21_test.go: -------------------------------------------------------------------------------- 1 | package labs21 2 | 3 | import "testing" 4 | 5 | func Benchmark_Go_Call_C(b *testing.B) { 6 | for i := 0; i < b.N; i++ { 7 | cfunc() 8 | } 9 | } 10 | 11 | func Benchmark_GO_Call_GO(b *testing.B) { 12 | for i := 0; i < b.N; i++ { 13 | gofunc() 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /labs12/README.md: -------------------------------------------------------------------------------- 1 | 测试jemalloc和malloc在go程序中是否有性能差别。 2 | 3 | 实验结果: 4 | 5 | dada-imac:labs dada$ go test -test.bench=".*" labs12 6 | PASS 7 | Benchmark_AllocAndFree 10000000 190 ns/op 8 | Benchmark_JeAllocAndFree 20000000 135 ns/op 9 | ok labs12 4.971s 10 | 11 | 实验结论:还是有差的 -------------------------------------------------------------------------------- /labs26/README.md: -------------------------------------------------------------------------------- 1 | 比较直接调用函数和反射调用函数的效率差别,忘记为什么目的测试的了。 2 | 3 | 测试结果: 4 | 5 | ``` 6 | $ go test -bench="." 7 | testing: warning: no tests to run 8 | PASS 9 | Benchmark_NormalFuncCall 2000000000 0.53 ns/op 10 | Benchmark_ReflectFuncCall 2000000 667 ns/op 11 | ok github.com/idada/go-labs/labs26 3.116s 12 | ``` -------------------------------------------------------------------------------- /labs18/README.md: -------------------------------------------------------------------------------- 1 | 测试switch和回调函数效率差异。 2 | 3 | 实验结果: 4 | 5 | ``` 6 | dada-imac:labs18 dada$ go test -bench=".*" 7 | testing: warning: no tests to run 8 | PASS 9 | Benchmark_UseSwitch 200000000 9.58 ns/op 10 | Benchmark_UseCallback 200000000 8.05 ns/op 11 | ok github.com/idada/go-labs/labs18 5.323s 12 | ``` 13 | -------------------------------------------------------------------------------- /labs20/labs20.go: -------------------------------------------------------------------------------- 1 | package labs20 2 | 3 | /* 4 | #include "labs20.h" 5 | */ 6 | import "C" 7 | 8 | //export go_func 9 | func go_func() { 10 | 11 | } 12 | 13 | func do_go_call_c(n int) { 14 | for i := 0; i < n; i++ { 15 | C.go_call_c() 16 | } 17 | } 18 | 19 | func do_c_call_go(n int) { 20 | C.c_call_go(C.int(n)) 21 | } 22 | -------------------------------------------------------------------------------- /labs02/README.md: -------------------------------------------------------------------------------- 1 | 测试值传参和指针传参的效率。 2 | 3 | 实验结果: 4 | 5 | dada-imac:misc dada$ go test -test.bench="." labs02 6 | testing: warning: no tests to run 7 | PASS 8 | Benchmark_Invoke1 2000000000 0.52 ns/op 9 | Benchmark_Invoke2 100000000 12.8 ns/op 10 | ok labs02 2.403s 11 | 12 | 结论:指针传参比值传参效率高很多。 -------------------------------------------------------------------------------- /labs18/labs18_test.go: -------------------------------------------------------------------------------- 1 | package labs18 2 | 3 | import "testing" 4 | 5 | func Benchmark_UseSwitch(b *testing.B) { 6 | obj := New() 7 | for i := 0; i < b.N; i++ { 8 | obj.UseSwitch() 9 | } 10 | } 11 | 12 | func Benchmark_UseCallback(b *testing.B) { 13 | obj := NewCallback() 14 | for i := 0; i < b.N; i++ { 15 | obj.UseCallback() 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /labs16/README.md: -------------------------------------------------------------------------------- 1 | 测试平方根算法的效率。 2 | 3 | 测试结果: 4 | 5 | ``` 6 | dada-imac:labs dada$ go test labs16 --bench="." 7 | testing: warning: no tests to run 8 | PASS 9 | Benchmark_Method1 500000 6677 ns/op 10 | Benchmark_Method2 500000000 6.48 ns/op 11 | Benchmark_Method3 500000000 3.73 ns/op 12 | ok labs16 9.558s 13 | ``` -------------------------------------------------------------------------------- /labs24/README.md: -------------------------------------------------------------------------------- 1 | 测试binary.Write和硬编码的效率差异。 2 | 3 | 测试结果: 4 | 5 | ``` 6 | dada-imac:labs24 dada$ go test -v -bench='.*' 7 | testing: warning: no tests to run 8 | PASS 9 | Benchmark_UseBinaryWrite1 50000000 68.5 ns/op 10 | Benchmark_UseBinaryWrite2 10000000 279 ns/op 11 | Benchmark_UseHardcode 100000000 21.5 ns/op 12 | ok github.com/idada/go-labs/labs24 8.771s 13 | ``` -------------------------------------------------------------------------------- /labs23/README.md: -------------------------------------------------------------------------------- 1 | 测试interface{}类型转换判断和布尔值判断效率差异。 2 | 3 | 测试结果: 4 | 5 | ``` 6 | dada-imac:labs23 dada$ go test -v -bench=".*" 7 | testing: warning: no tests to run 8 | PASS 9 | Benchmark_UseInterface1 100000000 10.4 ns/op 10 | Benchmark_UseInterface2 100000000 10.1 ns/op 11 | Benchmark_UseBoolean 100000000 13.2 ns/op 12 | ok github.com/idada/go-labs/labs23 3.410s 13 | ``` 14 | -------------------------------------------------------------------------------- /labs25/README.md: -------------------------------------------------------------------------------- 1 | 测试LockOSThread()对chan消息处理的影响,本来是希望通过LockOSThread()可以独占线程,避免chan通讯发生的调度开销,结果跟预期相反,由于调度算法没有改变,LockOSThread()的goroutine反而需要等待关联的线程空闲了才能被执行到,所以反而是变慢了。 2 | 3 | 测试结果: 4 | 5 | ``` 6 | $ go test -bench="." 7 | testing: warning: no tests to run 8 | PASS 9 | Benchmark_Normal 10000000 220 ns/op 10 | Benchmark_LockThread 1000000 2084 ns/op 11 | ok github.com/idada/go-labs/labs25 4.540s 12 | ``` -------------------------------------------------------------------------------- /labs01/README.md: -------------------------------------------------------------------------------- 1 | 测试类型判断和类型转换的效率。 2 | 3 | 执行结果: 4 | 5 | dada-imac:misc dada$ go test -test.bench=".*" labs01 6 | testing: warning: no tests to run 7 | PASS 8 | Benchmark_TypeSwitch 50000000 33.0 ns/op 9 | Benchmark_NormalSwitch 2000000000 1.99 ns/op 10 | Benchmark_InterfaceSwitch 100000000 18.4 ns/op 11 | ok labs 7.741s 12 | 13 | 结论:类型判断和类型转换这两个操作都比直接操作多几倍的消耗。 14 | 15 | -------------------------------------------------------------------------------- /labs04/README.md: -------------------------------------------------------------------------------- 1 | 测试range循环和for循环,以及结构体循环和指针循环的性能区别。 2 | 3 | 实验结果: 4 | 5 | dada-imac:misc dada$ go test -test.bench="." labs04 6 | testing: warning: no tests to run 7 | PASS 8 | Benchmark_Loop1 2000000 923 ns/op 9 | Benchmark_Loop2 2000000 819 ns/op 10 | Benchmark_Loop3 2000000 825 ns/op 11 | Benchmark_Loop4 100000 26230 ns/op 12 | ok labs04 10.640s 13 | 14 | 结论:对结构体列表的range循环最消耗性能,因为数据要重复复制。 -------------------------------------------------------------------------------- /labs17/README.md: -------------------------------------------------------------------------------- 1 | 尝试优化一段代码。 2 | 3 | 测试结果: 4 | 5 | ``` 6 | dada-imac:labs dada$ go test labs17 --bench="." 7 | PASS 8 | Benchmark_Method1 50000 53318 ns/op 9 | Benchmark_Method2 200000 11122 ns/op 10 | Benchmark_Method3 200000 9298 ns/op 11 | Benchmark_Method4 200000 8838 ns/op 12 | Benchmark_Method5 200000 8721 ns/op 13 | ok labs17 11.189s 14 | ``` 15 | 16 | 还可以再继续优化初始时候的数值转字符串,数值转字符串也是比较大的消耗。 -------------------------------------------------------------------------------- /labs19/README.md: -------------------------------------------------------------------------------- 1 | 测试缓存反射信息对效率的影响。 2 | 3 | ``` 4 | dada-imac:src dada$ go test labs19 --bench=".*" -v 5 | === RUN Test_Verify 6 | --- PASS: Test_Verify (0.00 seconds) 7 | === RUN Test_FastVerify 8 | --- PASS: Test_FastVerify (0.00 seconds) 9 | === RUN Test_VeryFastVerify 10 | --- PASS: Test_VeryFastVerify (0.00 seconds) 11 | PASS 12 | Benchmark_________Verify 1000000 1399 ns/op 13 | Benchmark_____FastVerify 10000000 178 ns/op 14 | Benchmark_VeryFastVerify 20000000 93.9 ns/op 15 | ok labs19 5.364s 16 | ``` -------------------------------------------------------------------------------- /labs03/README.md: -------------------------------------------------------------------------------- 1 | 测试对象创建的效率。 2 | 3 | 实验结果: 4 | 5 | dada-imac:misc dada$ go test -test.bench="." labs03 6 | testing: warning: no tests to run 7 | PASS 8 | Benchmark_NewStruct1 100000000 13.0 ns/op 9 | Benchmark_NewStruct2 100000000 24.5 ns/op 10 | Benchmark_NewStruct3 50000000 37.8 ns/op 11 | Benchmark_NewStruct4 100000000 25.1 ns/op 12 | Benchmark_NewStruct5 200000000 8.65 ns/op 13 | ok labs03 10.872s 14 | 15 | 结论:5和4的结果比较意外。 -------------------------------------------------------------------------------- /labs24/labs24_test.go: -------------------------------------------------------------------------------- 1 | package labs24 2 | 3 | import "testing" 4 | 5 | func Benchmark_UseBinaryWrite1(b *testing.B) { 6 | w := &DummyWriter{} 7 | for i := 0; i < b.N; i++ { 8 | UseBinaryWrite1(w, int32(i)) 9 | } 10 | } 11 | 12 | func Benchmark_UseBinaryWrite2(b *testing.B) { 13 | w := &DummyWriter{} 14 | for i := 0; i < b.N; i++ { 15 | UseBinaryWrite2(w, i) 16 | } 17 | } 18 | 19 | func Benchmark_UseHardcode(b *testing.B) { 20 | w := &DummyWriter{} 21 | for i := 0; i < b.N; i++ { 22 | UseHardcode(w, int32(i)) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /labs26/labs26_test.go: -------------------------------------------------------------------------------- 1 | package labs26 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | ) 7 | 8 | func MyFunc(a, b, c int) int { 9 | return a + b + c 10 | } 11 | 12 | func Benchmark_NormalFuncCall(b *testing.B) { 13 | for i := 0; i < b.N; i++ { 14 | MyFunc(i, i, i) 15 | } 16 | } 17 | 18 | func Benchmark_ReflectFuncCall(b *testing.B) { 19 | f := reflect.ValueOf(MyFunc) 20 | for i := 0; i < b.N; i++ { 21 | f.Call([]reflect.Value{ 22 | reflect.ValueOf(i), 23 | reflect.ValueOf(i), 24 | reflect.ValueOf(i), 25 | }) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /labs21/README.md: -------------------------------------------------------------------------------- 1 | Go的runtime包中使用goc机制实现Go的底层结构,所以判断goc机制应该不需要像cgo调用那样做防阻塞的保护,调用效率应该会高很多,这里做了一个测试goc机制调用c的实验。 2 | 3 | 实验结果: 4 | 5 | ``` 6 | $ go test -gcflags '-N' --bench="." 7 | testing: warning: no tests to run 8 | PASS 9 | Benchmark_Go_Call_C 500000000 3.84 ns/op 10 | Benchmark_GO_Call_GO 500000000 3.78 ns/op 11 | ok labs21 4.593s 12 | ``` 13 | 14 | 对比于labs20中的测试结果,效率的确高了很多,但是goc机制不允许包含标准c的头文件,是一个比较麻烦的事情,但是假设要用go实现一个脚本语言或调用脚本语言,用goc机制会获得更高的执行效率,当然实现起来代价也高了很多就是了。 15 | 16 | 如果可以找到一个快速把C的调用转换成类似runtime库中的.s文件那样的汇编代码,就可以做到无代价的包装C的库。 -------------------------------------------------------------------------------- /labs12/labs12_test.go: -------------------------------------------------------------------------------- 1 | package labs12 2 | 3 | import "testing" 4 | 5 | func Benchmark_AllocAndFree(b *testing.B) { 6 | for i := 0; i < b.N; i++ { 7 | AllocAndFree() 8 | } 9 | } 10 | 11 | func Benchmark_JeAllocAndFree(b *testing.B) { 12 | for i := 0; i < b.N; i++ { 13 | JeAllocAndFree() 14 | } 15 | } 16 | 17 | func Test_Nil(t *testing.T) { 18 | var a = NewBigStruct() 19 | 20 | if a.next != nil { 21 | t.Fail() 22 | } 23 | 24 | var b = NewXStruct() 25 | 26 | for i := 0; i < 100; i++ { 27 | if b.xyz[i] != nil { 28 | t.Fail() 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /labs15/labs15_test.go: -------------------------------------------------------------------------------- 1 | package labs15 2 | 3 | import "runtime" 4 | import "testing" 5 | 6 | func Benchmark_Fetch(b *testing.B) { 7 | for i := 0; i < b.N; i++ { 8 | temp := make([]MyTable, 0) 9 | 10 | FetchMyTable(func(item MyTable) { 11 | temp = append(temp, item) 12 | }) 13 | } 14 | 15 | runtime.GC() 16 | } 17 | 18 | func Benchmark_Lookup(b *testing.B) { 19 | for i := 0; i < b.N; i++ { 20 | temp := make([]*MyTable, 0) 21 | 22 | for j := 0; j < len(myTable); j++ { 23 | temp = append(temp, LookupMyTable(j)) 24 | } 25 | } 26 | 27 | runtime.GC() 28 | } 29 | -------------------------------------------------------------------------------- /labs06/README.md: -------------------------------------------------------------------------------- 1 | 测试小数据量循环和map取数据以及硬编码取数据的性能消耗。 2 | 3 | 试验结果: 4 | 5 | dada-imac:labs dada$ go test -test.bench="." labs06 6 | testing: warning: no tests to run 7 | PASS 8 | Benchmark_Loop1 500000000 5.73 ns/op 9 | Benchmark_Loop2 500000000 5.72 ns/op 10 | Benchmark_Loop3 50000000 68.0 ns/op 11 | Benchmark_Loop4 500000000 4.92 ns/op 12 | Benchmark_Loop5 500000000 4.40 ns/op 13 | ok labs06 15.970s 14 | 15 | 结论:硬编码 < 指针slice的range循环 < for循环,但是量级是一样的,看情况用。但是map差了一个量级,小数据量尽量少用。 16 | -------------------------------------------------------------------------------- /labs24/labs24.go: -------------------------------------------------------------------------------- 1 | package labs24 2 | 3 | import ( 4 | "encoding/binary" 5 | "io" 6 | ) 7 | 8 | type DummyWriter struct { 9 | } 10 | 11 | func (w *DummyWriter) Write(b []byte) (int, error) { 12 | return len(b), nil 13 | } 14 | 15 | func UseBinaryWrite1(w io.Writer, i int32) { 16 | binary.Write(w, binary.LittleEndian, i) 17 | } 18 | 19 | func UseBinaryWrite2(w io.Writer, i int) { 20 | binary.Write(w, binary.LittleEndian, i) 21 | } 22 | 23 | func UseHardcode(w io.Writer, i int32) { 24 | w.Write([]byte{ 25 | byte(i), 26 | byte(i >> 8), 27 | byte(i >> 16), 28 | byte(i >> 24), 29 | }) 30 | } 31 | -------------------------------------------------------------------------------- /labs23/labs23_test.go: -------------------------------------------------------------------------------- 1 | package labs23 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func Benchmark_UseInterface1(b *testing.B) { 8 | obj := &MyObject{Conn: new(BufferConn)} 9 | for i := 0; i < b.N; i++ { 10 | obj.UseInterface(i) 11 | } 12 | } 13 | 14 | func Benchmark_UseInterface2(b *testing.B) { 15 | obj := &MyObject{Conn: new(NormalConn)} 16 | for i := 0; i < b.N; i++ { 17 | obj.UseInterface(i) 18 | } 19 | } 20 | 21 | func Benchmark_UseBoolean(b *testing.B) { 22 | obj := &MyObject{UseBufferConn: true, Conn: new(BufferConn)} 23 | for i := 0; i < b.N; i++ { 24 | obj.UseBoolean(i) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /labs28/labs28_test.go: -------------------------------------------------------------------------------- 1 | package labs28 2 | 3 | import "testing" 4 | import "unsafe" 5 | 6 | func Test_ByteString(t *testing.T) { 7 | var x = []byte("Hello World!") 8 | var y = *(*string)(unsafe.Pointer(&x)) 9 | var z = string(x) 10 | 11 | if y != z { 12 | t.Fail() 13 | } 14 | } 15 | 16 | func Benchmark_Normal(b *testing.B) { 17 | var x = []byte("Hello World!") 18 | for i := 0; i < b.N; i ++ { 19 | _ = string(x) 20 | } 21 | } 22 | 23 | func Benchmark_ByteString(b *testing.B) { 24 | var x = []byte("Hello World!") 25 | for i := 0; i < b.N; i ++ { 26 | _ = *(*string)(unsafe.Pointer(&x)) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /labs09/labs09_test.go: -------------------------------------------------------------------------------- 1 | package labs09 2 | 3 | import "testing" 4 | 5 | func NormalFunc(i int) int { 6 | return i + 1 7 | } 8 | 9 | func Benchmark_NormalFuncCall(b *testing.B) { 10 | for i := 0; i < b.N; i++ { 11 | NormalFunc(i) 12 | } 13 | } 14 | 15 | func Benchmark_VarFuncCall1(b *testing.B) { 16 | for i := 0; i < b.N; i++ { 17 | VarFunc := func(i int) int { 18 | return i + 1 19 | } 20 | 21 | VarFunc(i) 22 | } 23 | } 24 | 25 | func Benchmark_VarFuncCall2(b *testing.B) { 26 | for i := 0; i < b.N; i++ { 27 | VarFunc := func() int { 28 | return i + 1 29 | } 30 | 31 | VarFunc() 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /labs22/README.md: -------------------------------------------------------------------------------- 1 | 尝试把CGO生成的runtime·cgocall替换为runtime·asmcgocall,调用开销显著下降。 2 | 3 | 实验过程和结果: 4 | 5 | ``` 6 | $ cd mylib/ 7 | $ go install 8 | $ cd .. 9 | $ go test -bench="." 10 | PASS 11 | Benchmark_Go_Call_C 50000000 74.1 ns/op 12 | ok labs23 3.782s 13 | $ go test -bench="." 14 | PASS 15 | Benchmark_Go_Call_C 50000000 54.7 ns/op 16 | ok labs23 2.805s 17 | $ cd mylib/ 18 | $ ./hack.sh 19 | $ cd .. 20 | $ go test -bench="." 21 | PASS 22 | Benchmark_Go_Call_C 100000000 11.8 ns/op 23 | ok labs23 1.203s 24 | $ go test -bench="." 25 | PASS 26 | Benchmark_Go_Call_C 100000000 12.2 ns/op 27 | ok labs23 1.247s 28 | ``` 29 | 30 | -------------------------------------------------------------------------------- /labs25/labs25_test.go: -------------------------------------------------------------------------------- 1 | package labs25 2 | 3 | import ( 4 | "runtime" 5 | "sync" 6 | "testing" 7 | ) 8 | 9 | var c1 = make(chan int) 10 | var c2 = make(chan int) 11 | 12 | func init() { 13 | var wg sync.WaitGroup 14 | wg.Add(1) 15 | go func() { 16 | wg.Done() 17 | for range c1 { 18 | } 19 | }() 20 | wg.Add(1) 21 | go func() { 22 | wg.Done() 23 | runtime.LockOSThread() 24 | for range c2 { 25 | } 26 | }() 27 | wg.Wait() 28 | } 29 | 30 | func Benchmark_Normal(b *testing.B) { 31 | for i := 0; i < b.N; i++ { 32 | c1 <- i 33 | } 34 | } 35 | 36 | func Benchmark_LockThread(b *testing.B) { 37 | for i := 0; i < b.N; i++ { 38 | c2 <- i 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /labs22/mylib/hack.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # make the code aways recompile 4 | echo "" >> mylib.go 5 | head -$((`cat mylib.go | wc -l`-1)) mylib.go > $$ && mv $$ mylib.go 6 | 7 | # record the install program 8 | go install -work -x 2> step2.sh 9 | 10 | # fix CGO_LDFLAGS format 11 | sed -i -e 's/"-g" "-O2"/"-g -O2"/g' step2.sh 12 | 13 | # fix go tool command 14 | sed -i -e 's/pack r/go tool pack r/g' step2.sh 15 | 16 | # the hack 17 | head -5 step2.sh > $$ && \ 18 | echo 'sed -i -e "s/runtime·cgocall/runtime·asmcgocall/g" `find $WORK/labs22/mylib/_obj/ -name *.c`' >> $$ && \ 19 | tail -n$((`cat step2.sh | wc -l`-5)) step2.sh >> $$ && \ 20 | mv $$ step2.sh 21 | 22 | sh step2.sh 23 | rm step2.* -------------------------------------------------------------------------------- /labs31/README.md: -------------------------------------------------------------------------------- 1 | 做内存池的时候有这样一个需求,给定一个数值,需要计算出这个数值落在2的第N次幂区间内,从而用这个N值索引出对应的池。 2 | 3 | 最直接的办法就是循环计算,因为2的20次幂就达到1M的大小了,这么大的内存块其实没有缓存的必要了,所以循环最多也就20次。 4 | 5 | 但是我很蛋疼了测试了sort包的Search函数,switch循环展开、if循环展开和人肉折半查找。 6 | 7 | 我电脑上测试结果如下: 8 | 9 | ``` 10 | $ go test -bench="." 11 | PASS 12 | Benchmark_Normal-4 50000000 25.6 ns/op 13 | Benchmark_Search-4 100000000 21.7 ns/op 14 | Benchmark_Switch-4 100000000 12.5 ns/op 15 | Benchmark_IF1-4 200000000 9.14 ns/op 16 | Benchmark_IF2-4 300000000 3.89 ns/op 17 | Benchmark_IF3-4 1000000000 2.37 ns/op 18 | ok github.com/idada/go-labs/labs31 11.822s 19 | ``` 20 | 21 | 呵呵,蛋好疼。 22 | 23 | 补充:最后一个IF3测试是由群里的v1zze同学提供的算法,果然牛逼。 -------------------------------------------------------------------------------- /labs13/README.md: -------------------------------------------------------------------------------- 1 | 测试不同数据结构的对象数量差别。 2 | 3 | 测试存储结构体和存储对象的map类型占用的对象数量: 4 | 5 | go run many_object1.go -gcflags '-N' | grep -o "HeapObjects.*" 6 | 7 | go run many_object2.go -gcflags '-N' | grep -o "HeapObjects.*" 8 | 9 | 测试存储结构体和存储对象的slice类型占用的对象数量: 10 | 11 | go run many_object3.go -gcflags '-N' | grep -o "HeapObjects.*" 12 | 13 | go run many_object4.go -gcflags '-N' | grep -o "HeapObjects.*" 14 | 15 | 未初始化的Slice和make后的Slice类型字段占用的对象数量: 16 | 17 | go run many_object5.go -gcflags '-N' | grep -o "HeapObjects.*" 18 | go run many_object6.go -gcflags '-N' | grep -o "HeapObjects.*" 19 | 20 | 实验结论: 21 | 22 | 1. 存对象指针的map和存结构体的map,每条数据都占用一个对象数量,两种数据结构无差异 23 | 2. 存对象的slice和存结构体的slice有明显差异,存结构体的slice不重复占用对象数量 24 | 3. 未初始化的对象类型字段是不占用对象数量的 25 | -------------------------------------------------------------------------------- /labs23/labs23.go: -------------------------------------------------------------------------------- 1 | package labs23 2 | 3 | type Conn interface { 4 | Writer(i int) int 5 | } 6 | 7 | type NormalConn struct { 8 | } 9 | 10 | func (c *NormalConn) Writer(i int) int { 11 | return i + 1000 12 | } 13 | 14 | type BufferConn struct { 15 | } 16 | 17 | func (c *BufferConn) Writer(i int) int { 18 | return i + 1000 19 | } 20 | 21 | type MyObject struct { 22 | UseBufferConn bool 23 | Conn Conn 24 | } 25 | 26 | func (obj *MyObject) UseInterface(i int) int { 27 | if conn, ok := obj.Conn.(*BufferConn); ok { 28 | return conn.Writer(i) 29 | } 30 | return obj.Conn.Writer(i) 31 | } 32 | 33 | func (obj *MyObject) UseBoolean(i int) int { 34 | if obj.UseBufferConn { 35 | return obj.Conn.(*BufferConn).Writer(i) 36 | } 37 | return obj.Conn.Writer(i) 38 | } 39 | -------------------------------------------------------------------------------- /labs13/many_object1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "os" 4 | import "runtime/pprof" 5 | 6 | type BigStruct struct { 7 | C01 int 8 | C02 int 9 | C03 int 10 | C04 int 11 | C05 int 12 | C06 int 13 | C07 int 14 | C08 int 15 | C09 int 16 | C10 int 17 | C11 int 18 | C12 int 19 | C13 int 20 | C14 int 21 | C15 int 22 | C16 int 23 | C17 int 24 | C18 int 25 | C19 int 26 | C20 int 27 | C21 int 28 | C22 int 29 | C23 int 30 | C24 int 31 | C25 int 32 | C26 int 33 | C27 int 34 | C28 int 35 | C29 int 36 | C30 int 37 | } 38 | 39 | var objects map[int]BigStruct 40 | 41 | func main() { 42 | objects = make(map[int]BigStruct) 43 | 44 | for i := 0; i < 10000; i++ { 45 | objects[i] = BigStruct{} 46 | } 47 | 48 | p := pprof.Lookup("heap") 49 | p.WriteTo(os.Stdout, 2) 50 | } 51 | -------------------------------------------------------------------------------- /labs13/many_object2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "os" 4 | import "runtime/pprof" 5 | 6 | type BigStruct struct { 7 | C01 int 8 | C02 int 9 | C03 int 10 | C04 int 11 | C05 int 12 | C06 int 13 | C07 int 14 | C08 int 15 | C09 int 16 | C10 int 17 | C11 int 18 | C12 int 19 | C13 int 20 | C14 int 21 | C15 int 22 | C16 int 23 | C17 int 24 | C18 int 25 | C19 int 26 | C20 int 27 | C21 int 28 | C22 int 29 | C23 int 30 | C24 int 31 | C25 int 32 | C26 int 33 | C27 int 34 | C28 int 35 | C29 int 36 | C30 int 37 | } 38 | 39 | var objects map[int]*BigStruct 40 | 41 | func main() { 42 | objects = make(map[int]*BigStruct) 43 | 44 | for i := 0; i < 10000; i++ { 45 | objects[i] = new(BigStruct) 46 | } 47 | 48 | p := pprof.Lookup("heap") 49 | p.WriteTo(os.Stdout, 2) 50 | } 51 | -------------------------------------------------------------------------------- /labs13/many_object5.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "os" 4 | import "runtime/pprof" 5 | 6 | type BigStruct struct { 7 | C01 []int 8 | C02 []int 9 | C03 []int 10 | C04 []int 11 | C05 []int 12 | C06 []int 13 | C07 []int 14 | C08 []int 15 | C09 []int 16 | C10 []int 17 | C11 []int 18 | C12 []int 19 | C13 []int 20 | C14 []int 21 | C15 []int 22 | C16 []int 23 | C17 []int 24 | C18 []int 25 | C19 []int 26 | C20 []int 27 | C21 []int 28 | C22 []int 29 | C23 []int 30 | C24 []int 31 | C25 []int 32 | C26 []int 33 | C27 []int 34 | C28 []int 35 | C29 []int 36 | C30 []int 37 | } 38 | 39 | func main() { 40 | data := make([]BigStruct, 1000) 41 | for i := 0; i < len(data); i++ { 42 | data[i] = BigStruct{} 43 | } 44 | p := pprof.Lookup("heap") 45 | p.WriteTo(os.Stdout, 2) 46 | } 47 | -------------------------------------------------------------------------------- /labs10/labs10.go: -------------------------------------------------------------------------------- 1 | package labs10 2 | 3 | import "unsafe" 4 | 5 | type BigStruct struct { 6 | next *BigStruct 7 | C01 int 8 | C02 int 9 | C03 int 10 | C04 int 11 | C05 int 12 | C06 int 13 | C07 int 14 | C08 int 15 | C09 int 16 | C10 int 17 | C11 int 18 | C12 int 19 | C13 int 20 | C14 int 21 | C15 int 22 | C16 int 23 | C17 int 24 | C18 int 25 | C19 int 26 | C20 int 27 | C21 int 28 | C22 int 29 | C23 int 30 | C24 int 31 | C25 int 32 | C26 int 33 | C27 int 34 | C28 int 35 | C29 int 36 | C30 int 37 | } 38 | 39 | var SizeOfBigStruct = int(unsafe.Sizeof(BigStruct{})) 40 | 41 | func NewBigStruct() *BigStruct { 42 | return (*BigStruct)(xnew(SizeOfBigStruct)) 43 | } 44 | 45 | func FreeBigStruct(p *BigStruct) { 46 | xfree(unsafe.Pointer(p)) 47 | } 48 | -------------------------------------------------------------------------------- /labs13/many_object3.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "os" 4 | import "runtime/pprof" 5 | 6 | type BigStruct struct { 7 | C01 int 8 | C02 int 9 | C03 int 10 | C04 int 11 | C05 int 12 | C06 int 13 | C07 int 14 | C08 int 15 | C09 int 16 | C10 int 17 | C11 int 18 | C12 int 19 | C13 int 20 | C14 int 21 | C15 int 22 | C16 int 23 | C17 int 24 | C18 int 25 | C19 int 26 | C20 int 27 | C21 int 28 | C22 int 29 | C23 int 30 | C24 int 31 | C25 int 32 | C26 int 33 | C27 int 34 | C28 int 35 | C29 int 36 | C30 int 37 | } 38 | 39 | var objects []BigStruct 40 | 41 | func main() { 42 | objects = make([]BigStruct, 0, 10000) 43 | 44 | for i := 0; i < 10000; i++ { 45 | objects = append(objects, BigStruct{}) 46 | } 47 | 48 | p := pprof.Lookup("heap") 49 | p.WriteTo(os.Stdout, 2) 50 | } 51 | -------------------------------------------------------------------------------- /labs13/many_object4.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "os" 4 | import "runtime/pprof" 5 | 6 | type BigStruct struct { 7 | C01 int 8 | C02 int 9 | C03 int 10 | C04 int 11 | C05 int 12 | C06 int 13 | C07 int 14 | C08 int 15 | C09 int 16 | C10 int 17 | C11 int 18 | C12 int 19 | C13 int 20 | C14 int 21 | C15 int 22 | C16 int 23 | C17 int 24 | C18 int 25 | C19 int 26 | C20 int 27 | C21 int 28 | C22 int 29 | C23 int 30 | C24 int 31 | C25 int 32 | C26 int 33 | C27 int 34 | C28 int 35 | C29 int 36 | C30 int 37 | } 38 | 39 | var objects []*BigStruct 40 | 41 | func main() { 42 | objects = make([]*BigStruct, 0, 10000) 43 | 44 | for i := 0; i < 10000; i++ { 45 | objects = append(objects, new(BigStruct)) 46 | } 47 | 48 | p := pprof.Lookup("heap") 49 | p.WriteTo(os.Stdout, 2) 50 | } 51 | -------------------------------------------------------------------------------- /labs16/labs16_test.go: -------------------------------------------------------------------------------- 1 | package labs16 2 | 3 | import ( 4 | "math" 5 | "testing" 6 | "unsafe" 7 | ) 8 | 9 | func Benchmark_Method1(b *testing.B) { 10 | for m := 0; m < b.N; m++ { 11 | var x = float32(10012312312) 12 | var z = 0.5 * x 13 | for i := 0; i < 1000; i++ { 14 | z -= (z*z - x) / (2 * x) 15 | } 16 | } 17 | } 18 | 19 | func Benchmark_Method2(b *testing.B) { 20 | for m := 0; m < b.N; m++ { 21 | var x = float32(10012312312) 22 | var xhalf = 0.5 * x 23 | 24 | i := *(*int32)(unsafe.Pointer(&x)) 25 | i = 0x5f3759df - (i >> 1) 26 | x = *(*float32)(unsafe.Pointer(&i)) 27 | x = x * (1.5 - xhalf*x*x) 28 | x = x * (1.5 - xhalf*x*x) 29 | x = 1 / x 30 | } 31 | } 32 | 33 | func Benchmark_Method3(b *testing.B) { 34 | for m := 0; m < b.N; m++ { 35 | math.Sqrt(10012312312) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /labs07/README.md: -------------------------------------------------------------------------------- 1 | 测试几种链表遍历查找的性能差异。 2 | 3 | 实验结果: 4 | 5 | dada-imac:labs dada$ go test -test.bench="." labs07 6 | PASS 7 | Benchmark_Loop1 500000 4386 ns/op 8 | Benchmark_Loop2 500000 5206 ns/op 9 | Benchmark_Loop3 100000 14821 ns/op 10 | Benchmark_Loop4 10000 135384 ns/op 11 | Benchmark_Loop5 5000 607735 ns/op 12 | Benchmark_Loop6 500000 7067 ns/op 13 | ok labs07 14.618s 14 | 15 | 确认算法有效: 16 | 17 | dada-imac:labs dada$ go test labs07 -v 18 | === RUN Test_Loop4 19 | --- PASS: Test_Loop4 (0.00 seconds) 20 | === RUN Test_Loop5 21 | --- PASS: Test_Loop5 (0.00 seconds) 22 | === RUN Test_Loop6 23 | --- PASS: Test_Loop6 (0.00 seconds) 24 | PASS 25 | ok labs07 0.016s 26 | 27 | 结论:有空做个查询表达式解析器吧。 -------------------------------------------------------------------------------- /labs09/README.md: -------------------------------------------------------------------------------- 1 | 测试匿名函数和普通函数的调用消耗。 2 | 3 | 禁用优化前: 4 | 5 | dada-imac:labs dada$ go test -test.bench="." labs09 6 | testing: warning: no tests to run 7 | PASS 8 | Benchmark_NormalFuncCall 2000000000 0.52 ns/op 9 | Benchmark_VarFuncCall1 2000000000 1.84 ns/op 10 | Benchmark_VarFuncCall2 1000000000 2.16 ns/op 11 | ok labs09 7.347s 12 | 13 | 禁用优化后: 14 | 15 | dada-imac:labs dada$ go test -test.bench="." -gcflags '-N' labs09 16 | testing: warning: no tests to run 17 | PASS 18 | Benchmark_NormalFuncCall 2000000000 1.99 ns/op 19 | Benchmark_VarFuncCall1 1000000000 2.02 ns/op 20 | Benchmark_VarFuncCall2 50000000 58.8 ns/op 21 | ok labs09 9.412s 22 | 23 | 结论:测试中用的是一个很简单的函数,所以很容易被新版的go做内联优化,禁用优化前后结果差别明显,如果不考虑优化,匿名函数和普通函数调用是一个量级的消耗,差别甚微。但是普通函数比较有可能被优化。在没有优化的情况下,闭包函数消耗又要再高一个量级。 -------------------------------------------------------------------------------- /labs08/README.md: -------------------------------------------------------------------------------- 1 | 同labs07,区别是用slice替代链表结构。 2 | 3 | 试验结果: 4 | 5 | dada-imac:labs dada$ go test -test.bench="." labs08 6 | PASS 7 | Benchmark_Loop1 2000000 837 ns/op 8 | Benchmark_Loop2 1000000 2671 ns/op 9 | Benchmark_Loop3 100000 15072 ns/op 10 | Benchmark_Loop4 10000 130577 ns/op 11 | Benchmark_Loop5 5000 606500 ns/op 12 | Benchmark_Loop6 500000 7145 ns/op 13 | ok labs08 4.959s 14 | dada-imac:labs dada$ go test -test.bench="." labs07 15 | PASS 16 | Benchmark_Loop1 500000 4386 ns/op 17 | Benchmark_Loop2 500000 5206 ns/op 18 | Benchmark_Loop3 100000 14821 ns/op 19 | Benchmark_Loop4 10000 135384 ns/op 20 | Benchmark_Loop5 5000 607735 ns/op 21 | Benchmark_Loop6 500000 7067 ns/op 22 | ok labs07 14.618s 23 | 24 | 结论:简单循环slice明显更快,但是加入查询后, slice的优势就可以忽略不计了。 25 | -------------------------------------------------------------------------------- /labs02/labs02_test.go: -------------------------------------------------------------------------------- 1 | package labs02 2 | 3 | import "testing" 4 | 5 | type BigStruct struct { 6 | C01 uint64 7 | C02 uint64 8 | C03 uint64 9 | C04 uint64 10 | C05 uint64 11 | C06 uint64 12 | C07 uint64 13 | C08 uint64 14 | C09 uint64 15 | C10 uint64 16 | C11 uint64 17 | C12 uint64 18 | C13 uint64 19 | C14 uint64 20 | C15 uint64 21 | C16 uint64 22 | C17 uint64 23 | C18 uint64 24 | C19 uint64 25 | C20 uint64 26 | C21 uint64 27 | C22 uint64 28 | C23 uint64 29 | C24 uint64 30 | C25 uint64 31 | C26 uint64 32 | C27 uint64 33 | C28 uint64 34 | C29 uint64 35 | C30 uint64 36 | } 37 | 38 | func Invoke1(a *BigStruct) uint64 { 39 | return a.C30 40 | } 41 | 42 | func Invoke2(a BigStruct) uint64 { 43 | return a.C30 44 | } 45 | 46 | func Benchmark_Invoke1(b *testing.B) { 47 | var a = new(BigStruct) 48 | 49 | for i := 0; i < b.N; i++ { 50 | Invoke1(a) 51 | } 52 | } 53 | 54 | func Benchmark_Invoke2(b *testing.B) { 55 | var a = BigStruct{} 56 | 57 | for i := 0; i < b.N; i++ { 58 | Invoke2(a) 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /labs18/labs18.go: -------------------------------------------------------------------------------- 1 | package labs18 2 | 3 | import "encoding/binary" 4 | 5 | type MyObject struct { 6 | n int 7 | head []byte 8 | callback func([]byte) int 9 | bo binary.ByteOrder 10 | } 11 | 12 | func New() *MyObject { 13 | return &MyObject{ 14 | n: 4, 15 | head: make([]byte, 4), 16 | bo: binary.LittleEndian, 17 | } 18 | } 19 | 20 | func NewCallback() *MyObject { 21 | return &MyObject{ 22 | n: 4, 23 | head: make([]byte, 4), 24 | callback: func(head []byte) int { 25 | return int(binary.LittleEndian.Uint32(head)) + 10 26 | }, 27 | } 28 | } 29 | 30 | func (obj *MyObject) UseSwitch() int { 31 | size := 0 32 | 33 | switch obj.n { 34 | case 1: 35 | size = int(obj.head[0]) 36 | case 2: 37 | size = int(obj.bo.Uint16(obj.head)) 38 | case 4: 39 | size = int(obj.bo.Uint32(obj.head)) 40 | case 8: 41 | size = int(obj.bo.Uint64(obj.head)) 42 | default: 43 | panic("unsupported packet head size") 44 | } 45 | 46 | return size + 10 47 | } 48 | 49 | func (obj *MyObject) UseCallback() int { 50 | return obj.callback(obj.head) 51 | } 52 | -------------------------------------------------------------------------------- /labs01/labs01_test.go: -------------------------------------------------------------------------------- 1 | package labs01 2 | 3 | import "testing" 4 | 5 | type InterfaceA interface { 6 | AA() 7 | } 8 | 9 | type InterfaceB interface { 10 | BB() 11 | } 12 | 13 | type A struct { 14 | v int 15 | } 16 | 17 | func (a *A) AA() { 18 | a.v += 1 19 | } 20 | 21 | type B struct { 22 | v int 23 | } 24 | 25 | func (b *B) BB() { 26 | b.v += 1 27 | } 28 | 29 | func TypeSwitch(v interface{}) { 30 | switch v.(type) { 31 | case InterfaceA: 32 | v.(InterfaceA).AA() 33 | case InterfaceB: 34 | v.(InterfaceB).BB() 35 | } 36 | } 37 | 38 | func NormalSwitch(a *A) { 39 | a.AA() 40 | } 41 | 42 | func InterfaceSwitch(v interface{}) { 43 | v.(InterfaceA).AA() 44 | } 45 | 46 | func Benchmark_TypeSwitch(b *testing.B) { 47 | var a = new(A) 48 | 49 | for i := 0; i < b.N; i++ { 50 | TypeSwitch(a) 51 | } 52 | } 53 | 54 | func Benchmark_NormalSwitch(b *testing.B) { 55 | var a = new(A) 56 | 57 | for i := 0; i < b.N; i++ { 58 | NormalSwitch(a) 59 | } 60 | } 61 | 62 | func Benchmark_InterfaceSwitch(b *testing.B) { 63 | var a = new(A) 64 | 65 | for i := 0; i < b.N; i++ { 66 | InterfaceSwitch(a) 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /labs14/cgo_string.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | /* 4 | #include 5 | #include 6 | */ 7 | import "C" 8 | import "reflect" 9 | import "unsafe" 10 | import "strconv" 11 | 12 | type SomeStruct struct { 13 | Id int 14 | Name string 15 | } 16 | 17 | var someData []SomeStruct 18 | 19 | func init() { 20 | data := new(reflect.SliceHeader) 21 | data.Cap = 10 22 | data.Len = 10 23 | data.Data = uintptr(C.calloc(1, C.size_t(unsafe.Sizeof(SomeStruct{})))) 24 | 25 | someData = *(*[]SomeStruct)(unsafe.Pointer(data)) 26 | 27 | for i := 0; i < len(someData); i++ { 28 | someData[i] = SomeStruct{ 29 | Id: i, 30 | Name: "你好" + strconv.Itoa(i), 31 | } 32 | } 33 | } 34 | 35 | func takeData(i int) SomeStruct { 36 | return someData[i] 37 | } 38 | 39 | func fetchData(callback func(s SomeStruct)) { 40 | for i := 0; i < len(someData); i++ { 41 | callback(someData[i]) 42 | } 43 | } 44 | 45 | func main() { 46 | for i := 0; i < len(someData); i++ { 47 | println(takeData(i).Name) 48 | } 49 | 50 | var data []SomeStruct 51 | 52 | fetchData(func(item SomeStruct) { 53 | data = append(data, item) 54 | }) 55 | 56 | for i := 0; i < len(data); i++ { 57 | println(data[i].Name) 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 一些杂七杂八脑洞大开的实验: 2 | 3 | | 实验 | 描述 | 4 | | ------ | ------ | 5 | | labs01 | 测试类型判断和类型转换的效率 | 6 | | labs02 | 测试值传参和指针传参的效率 | 7 | | labs03 | 测试对象创建的效率 | 8 | | labs04 | 测试range循环和for循环,以及结构体循环和指针循环的性能区别 | 9 | | labs05 | 测试整数和浮点数的运算效率 | 10 | | labs06 | 测试小数据量循环和map取数据以及硬编码取数据的性能消耗 | 11 | | labs07 | 测试几种链表遍历查找的性能差异 | 12 | | labs08 | 同labs07,区别是用slice替代链表结构 | 13 | | labs09 | 测试匿名函数和普通函数的调用消耗 | 14 | | labs10 | 尝试绕过gc扫描 | 15 | | labs11 | 测试json序列化支持的类型 | 16 | | labs12 | 测试jsmalloc和malloc在go程序中是否有性能差别 | 17 | | labs13 | 测试不同数据结构的对象数量差别 | 18 | | labs14 | 测试用cgo复制go的内存数据和还原数据 | 19 | | labs15 | 测试unsafe伪造slice数据结构做内存表的查询效率 | 20 | | labs16 | 测试平方根算法的效率 | 21 | | labs17 | 尝试优化一段代码 | 22 | | labs18 | 测试switch和回调函数效率差异 | 23 | | labs19 | 测试缓存反射信息对效率的影响 | 24 | | labs20 | 测试Go调用C和C调用Go的效率差异 | 25 | | labs21 | 个测试goc机制调用c的实验 | 26 | | labs22 | 尝试把CGO生成的runtime·cgocall替换为runtime·asmcgocall | 27 | | labs23 | 测试interface{}类型转换判断和布尔值判断效率差异 | 28 | | labs24 | 测试binary.Write和硬编码的效率差异 | 29 | | labs25 | 测试LockOSThread()对chan消息处理的影响 | 30 | | labs26 | 比较直接调用函数和反射调用函数的效率差别 | 31 | | labs27 | 测试不修改runtime代码的情况下获取goid的效率 | 32 | | labs28 | 测试`[]byte`转`string`的效率 | 33 | | labs29 | 测试不同压缩算法压缩json数据的压缩比和压缩效率。| 34 | | labs30 | 内存数据库事务Demo | 35 | | labs31 | 计算一个值在2的第N次幂区间(蛋疼的性能测试)| -------------------------------------------------------------------------------- /labs15/demo_db.go: -------------------------------------------------------------------------------- 1 | package labs15 2 | 3 | /* 4 | #include 5 | */ 6 | import "C" 7 | import "unsafe" 8 | import "reflect" 9 | 10 | type MyTable struct { 11 | C01 int 12 | C02 int 13 | C03 int 14 | C04 int 15 | C05 int 16 | C06 int 17 | C07 int 18 | C08 int 19 | C09 int 20 | C10 int 21 | Child *ChildData 22 | } 23 | 24 | type ChildData struct { 25 | C01 int 26 | C02 int 27 | C03 int 28 | C04 int 29 | C05 int 30 | C06 int 31 | C07 int 32 | C08 int 33 | C09 int 34 | C10 int 35 | } 36 | 37 | var myTable []MyTable 38 | 39 | func init() { 40 | size := 100000 41 | head := (*reflect.SliceHeader)(unsafe.Pointer(&myTable)) 42 | head.Data = uintptr(C.calloc(C.size_t(size), C.size_t(unsafe.Sizeof(MyTable{})))) 43 | head.Cap = size 44 | head.Len = size 45 | 46 | sizeofChildData := C.size_t(unsafe.Sizeof(ChildData{})) 47 | 48 | for i := 0; i < size; i++ { 49 | myTable[i].C01 = i 50 | myTable[i].Child = (*ChildData)(C.calloc(1, sizeofChildData)) 51 | myTable[i].Child.C01 = i 52 | } 53 | } 54 | 55 | func FetchMyTable(callback func(item MyTable)) { 56 | for i := 0; i < len(myTable); i++ { 57 | callback(myTable[i]) 58 | } 59 | } 60 | 61 | func LookupMyTable(i int) *MyTable { 62 | temp := myTable[i] 63 | return &temp 64 | } 65 | -------------------------------------------------------------------------------- /labs12/labs12.go: -------------------------------------------------------------------------------- 1 | package labs12 2 | 3 | /* 4 | #cgo LDFLAGS: -ljemalloc 5 | #include 6 | #include 7 | */ 8 | import "C" 9 | import "unsafe" 10 | 11 | type BigStruct struct { 12 | next *BigStruct 13 | C01 int 14 | C02 int 15 | C03 int 16 | C04 int 17 | C05 int 18 | C06 int 19 | C07 int 20 | C08 int 21 | C09 int 22 | C10 int 23 | C11 int 24 | C12 int 25 | C13 int 26 | C14 int 27 | C15 int 28 | C16 int 29 | C17 int 30 | C18 int 31 | C19 int 32 | C20 int 33 | C21 int 34 | C22 int 35 | C23 int 36 | C24 int 37 | C25 int 38 | C26 int 39 | C27 int 40 | C28 int 41 | C29 int 42 | C30 int 43 | } 44 | 45 | type XStruct struct { 46 | xyz []*BigStruct 47 | } 48 | 49 | var sizeof_XStruct = C.size_t(unsafe.Sizeof(XStruct{})) 50 | var sizeof_BigStruct = C.size_t(unsafe.Sizeof(BigStruct{})) 51 | 52 | func NewBigStruct() *BigStruct { 53 | return (*BigStruct)(C.calloc(1, sizeof_BigStruct)) 54 | } 55 | 56 | func NewXStruct() *XStruct { 57 | var r = (*XStruct)(C.calloc(1, sizeof_XStruct)) 58 | r.xyz = make([]*BigStruct, 100) 59 | return r 60 | } 61 | 62 | func AllocAndFree() { 63 | var ptr = C.malloc(sizeof_BigStruct) 64 | 65 | C.free(ptr) 66 | } 67 | 68 | func JeAllocAndFree() { 69 | var ptr = C.je_malloc(sizeof_BigStruct) 70 | 71 | C.je_free(ptr) 72 | } 73 | -------------------------------------------------------------------------------- /labs19/labs19_test.go: -------------------------------------------------------------------------------- 1 | package labs19 2 | 3 | import "testing" 4 | 5 | type MyTable struct { 6 | Name1 string `max-length:"10"` 7 | Name2 string `max-length:"10"` 8 | Name3 string `max-length:"10"` 9 | Name4 string `max-length:"10"` 10 | Name5 string `max-length:"10"` 11 | Name6 string `max-length:"10"` 12 | Name7 string `max-length:"10"` 13 | } 14 | 15 | func Test_Verify(t *testing.T) { 16 | x := new(MyTable) 17 | x.Name7 = "012" 18 | 19 | if Verify(x) != nil { 20 | t.FailNow() 21 | } 22 | 23 | x.Name7 = "0123456789A" 24 | 25 | if Verify(x) == nil { 26 | t.FailNow() 27 | } 28 | } 29 | 30 | func Test_FastVerify(t *testing.T) { 31 | x := new(MyTable) 32 | x.Name7 = "012" 33 | 34 | if FastVerify(x) != nil { 35 | t.FailNow() 36 | } 37 | 38 | x.Name7 = "0123456789A" 39 | 40 | if FastVerify(x) == nil { 41 | t.FailNow() 42 | } 43 | } 44 | 45 | func Test_VeryFastVerify(t *testing.T) { 46 | x := new(MyTable) 47 | x.Name7 = "012" 48 | 49 | if VeryFastVerify(x) != nil { 50 | t.FailNow() 51 | } 52 | 53 | x.Name7 = "0123456789A" 54 | 55 | if VeryFastVerify(x) == nil { 56 | t.FailNow() 57 | } 58 | } 59 | 60 | func Benchmark_________Verify(b *testing.B) { 61 | x := new(MyTable) 62 | 63 | for i := 0; i < b.N; i++ { 64 | Verify(x) 65 | } 66 | } 67 | 68 | func Benchmark_____FastVerify(b *testing.B) { 69 | x := new(MyTable) 70 | 71 | for i := 0; i < b.N; i++ { 72 | FastVerify(x) 73 | } 74 | } 75 | 76 | func Benchmark_VeryFastVerify(b *testing.B) { 77 | x := new(MyTable) 78 | 79 | for i := 0; i < b.N; i++ { 80 | VeryFastVerify(x) 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /labs29/README.md: -------------------------------------------------------------------------------- 1 | 测试不同压缩算法压缩json数据的压缩比和压缩效率。 2 | 3 | 实验结果: 4 | 5 | ``` 6 | dada-imac:labs29 dada$ go test -v 7 | === RUN Test_Normal 8 | --- PASS: Test_Normal (0.16s) 9 | === RUN Test_Gzip_Level1 10 | --- PASS: Test_Gzip_Level1 (0.13s) 11 | === RUN Test_Gzip_Level5 12 | --- PASS: Test_Gzip_Level5 (0.15s) 13 | === RUN Test_Gzip_Level9 14 | --- PASS: Test_Gzip_Level9 (0.15s) 15 | === RUN Test_Snappy 16 | --- PASS: Test_Snappy (0.14s) 17 | === RUN Test_Normal_10S 18 | --- PASS: Test_Normal_10S (10.00s) 19 | labs29_test.go:155: 28 MB/S 20 | === RUN Test_Gzip_10S_Level1 21 | --- PASS: Test_Gzip_10S_Level1 (10.00s) 22 | labs29_test.go:173: 29 MB/S 23 | === RUN Test_Gzip_10S_Level5 24 | --- PASS: Test_Gzip_10S_Level5 (10.00s) 25 | labs29_test.go:191: 27 MB/S 26 | === RUN Test_Gzip_10S_Level9 27 | --- PASS: Test_Gzip_10S_Level9 (10.00s) 28 | labs29_test.go:208: 25 MB/S 29 | === RUN Test_Snappy2_10S 30 | --- PASS: Test_Snappy2_10S (10.00s) 31 | labs29_test.go:224: 21 MB/S 32 | PASS 33 | ok github.com/idada/go-labs/labs29 50.738s 34 | 35 | dada-imac:labs29 dada$ ls -lah 36 | total 9192 37 | drwxr-xr-x@ 10 dada staff 340B 4 22 01:54 . 38 | drwxr-xr-x@ 34 dada staff 1.1K 4 22 00:05 .. 39 | -rw-r--r--@ 1 dada staff 1.6K 4 22 09:24 README.md 40 | -rwxr-xr-x@ 1 dada staff 45K 4 22 09:22 json.gzip1 41 | -rwxr-xr-x@ 1 dada staff 25K 4 22 09:22 json.gzip5 42 | -rwxr-xr-x@ 1 dada staff 18K 4 22 09:22 json.gzip9 43 | -rwxr-xr-x@ 1 dada staff 4.0M 4 22 09:22 json.normal 44 | -rwxr-xr-x@ 1 dada staff 399K 4 22 09:22 json.snappy 45 | -rw-r--r--@ 1 dada staff 4.0K 4 22 09:22 labs29_test.go 46 | ``` 47 | 48 | 实验结论:实验证明各种流压缩算法的吞吐量都高于json序列化过程,所以没必要用太高级压缩算法,可以用最高压缩比gzip -------------------------------------------------------------------------------- /labs13/many_object6.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "os" 4 | import "runtime/pprof" 5 | 6 | type BigStruct struct { 7 | C01 []int 8 | C02 []int 9 | C03 []int 10 | C04 []int 11 | C05 []int 12 | C06 []int 13 | C07 []int 14 | C08 []int 15 | C09 []int 16 | C10 []int 17 | C11 []int 18 | C12 []int 19 | C13 []int 20 | C14 []int 21 | C15 []int 22 | C16 []int 23 | C17 []int 24 | C18 []int 25 | C19 []int 26 | C20 []int 27 | C21 []int 28 | C22 []int 29 | C23 []int 30 | C24 []int 31 | C25 []int 32 | C26 []int 33 | C27 []int 34 | C28 []int 35 | C29 []int 36 | C30 []int 37 | } 38 | 39 | func main() { 40 | data := make([]BigStruct, 1000) 41 | for i := 0; i < len(data); i++ { 42 | data[i] = BigStruct{ 43 | C01: make([]int, 0, 1), 44 | C02: make([]int, 0, 1), 45 | C03: make([]int, 0, 1), 46 | C04: make([]int, 0, 1), 47 | C05: make([]int, 0, 1), 48 | C06: make([]int, 0, 1), 49 | C07: make([]int, 0, 1), 50 | C08: make([]int, 0, 1), 51 | C09: make([]int, 0, 1), 52 | C10: make([]int, 0, 1), 53 | C11: make([]int, 0, 1), 54 | C12: make([]int, 0, 1), 55 | C13: make([]int, 0, 1), 56 | C14: make([]int, 0, 1), 57 | C15: make([]int, 0, 1), 58 | C16: make([]int, 0, 1), 59 | C17: make([]int, 0, 1), 60 | C18: make([]int, 0, 1), 61 | C19: make([]int, 0, 1), 62 | C20: make([]int, 0, 1), 63 | C21: make([]int, 0, 1), 64 | C22: make([]int, 0, 1), 65 | C23: make([]int, 0, 1), 66 | C24: make([]int, 0, 1), 67 | C25: make([]int, 0, 1), 68 | C26: make([]int, 0, 1), 69 | C27: make([]int, 0, 1), 70 | C28: make([]int, 0, 1), 71 | C29: make([]int, 0, 1), 72 | C30: make([]int, 0, 1), 73 | } 74 | } 75 | p := pprof.Lookup("heap") 76 | p.WriteTo(os.Stdout, 2) 77 | } 78 | -------------------------------------------------------------------------------- /labs07/labs07.go: -------------------------------------------------------------------------------- 1 | package labs07 2 | 3 | import "reflect" 4 | import "unsafe" 5 | 6 | type BigStruct struct { 7 | next *BigStruct 8 | C01 int 9 | C02 int 10 | C03 int 11 | C04 int 12 | C05 int 13 | C06 int 14 | C07 int 15 | C08 int 16 | C09 int 17 | C10 int 18 | C11 int 19 | C12 int 20 | C13 int 21 | C14 int 22 | C15 int 23 | C16 int 24 | C17 int 25 | C18 int 26 | C19 int 27 | C20 int 28 | C21 int 29 | C22 int 30 | C23 int 31 | C24 int 32 | C25 int 33 | C26 int 34 | C27 int 35 | C28 int 36 | C29 int 37 | C30 int 38 | } 39 | 40 | // operator 41 | const OP_EQ = 0 // == 42 | 43 | // type 44 | const TP_INT = 0 // int 45 | 46 | type Query struct { 47 | conditions []*Condition 48 | } 49 | 50 | type Condition struct { 51 | op int 52 | tp int 53 | offset uintptr 54 | value unsafe.Pointer 55 | } 56 | 57 | func (q *Query) Match(n *BigStruct) bool { 58 | var nn = uintptr(unsafe.Pointer(n)) 59 | for _, c := range q.conditions { 60 | if c.Match(nn) == false { 61 | return false 62 | } 63 | } 64 | return true 65 | } 66 | 67 | func (c *Condition) Match(n uintptr) bool { 68 | switch c.op { 69 | case OP_EQ: 70 | var b = unsafe.Pointer(n + c.offset) 71 | switch c.tp { 72 | case TP_INT: 73 | return *(*int)(c.value) == *(*int)(b) 74 | } 75 | } 76 | return false 77 | } 78 | 79 | func NewQuery(name string, operator string, value int) *Query { 80 | var t = reflect.TypeOf(BigStruct{}) 81 | var f, _ = t.FieldByName(name) 82 | 83 | var op int 84 | switch operator { 85 | case "==": 86 | op = OP_EQ 87 | } 88 | 89 | return &Query{ 90 | []*Condition{ 91 | &Condition{ 92 | op: op, 93 | tp: TP_INT, 94 | offset: f.Offset, 95 | value: unsafe.Pointer(&value), 96 | }, 97 | }, 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /labs08/labs08.go: -------------------------------------------------------------------------------- 1 | package labs08 2 | 3 | import "reflect" 4 | import "unsafe" 5 | 6 | type BigStruct struct { 7 | next *BigStruct 8 | C01 int 9 | C02 int 10 | C03 int 11 | C04 int 12 | C05 int 13 | C06 int 14 | C07 int 15 | C08 int 16 | C09 int 17 | C10 int 18 | C11 int 19 | C12 int 20 | C13 int 21 | C14 int 22 | C15 int 23 | C16 int 24 | C17 int 25 | C18 int 26 | C19 int 27 | C20 int 28 | C21 int 29 | C22 int 30 | C23 int 31 | C24 int 32 | C25 int 33 | C26 int 34 | C27 int 35 | C28 int 36 | C29 int 37 | C30 int 38 | } 39 | 40 | // operator 41 | const OP_EQ = 0 // == 42 | 43 | // type 44 | const TP_INT = 0 // int 45 | 46 | type Query struct { 47 | conditions []*Condition 48 | } 49 | 50 | type Condition struct { 51 | op int 52 | tp int 53 | offset uintptr 54 | value unsafe.Pointer 55 | } 56 | 57 | func (q *Query) Match(n *BigStruct) bool { 58 | var nn = uintptr(unsafe.Pointer(n)) 59 | for _, c := range q.conditions { 60 | if c.Match(nn) == false { 61 | return false 62 | } 63 | } 64 | return true 65 | } 66 | 67 | func (c *Condition) Match(n uintptr) bool { 68 | switch c.op { 69 | case OP_EQ: 70 | var b = unsafe.Pointer(n + c.offset) 71 | switch c.tp { 72 | case TP_INT: 73 | return *(*int)(c.value) == *(*int)(b) 74 | } 75 | } 76 | return false 77 | } 78 | 79 | func NewQuery(name string, operator string, value int) *Query { 80 | var t = reflect.TypeOf(BigStruct{}) 81 | var f, _ = t.FieldByName(name) 82 | 83 | var op int 84 | switch operator { 85 | case "==": 86 | op = OP_EQ 87 | } 88 | 89 | return &Query{ 90 | []*Condition{ 91 | &Condition{ 92 | op: op, 93 | tp: TP_INT, 94 | offset: f.Offset, 95 | value: unsafe.Pointer(&value), 96 | }, 97 | }, 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /labs05/README.md: -------------------------------------------------------------------------------- 1 | 测试整数和浮点数的运算效率。 2 | 3 | 实验结果: 4 | 5 | dada-imac:labs dada$ go test -test.bench="." labs05 6 | testing: warning: no tests to run 7 | PASS 8 | Benchmark_IntAdd 2000000000 0.28 ns/op 9 | Benchmark_Int8Add 2000000000 0.28 ns/op 10 | Benchmark_Int16Add 2000000000 0.28 ns/op 11 | Benchmark_Int32Add 2000000000 0.28 ns/op 12 | Benchmark_Int64Add 2000000000 0.28 ns/op 13 | Benchmark_Float32Add 2000000000 1.05 ns/op 14 | Benchmark_Float64Add 2000000000 0.79 ns/op 15 | Benchmark_IntSub 2000000000 0.28 ns/op 16 | Benchmark_Int8Sub 2000000000 0.28 ns/op 17 | Benchmark_Int16Sub 2000000000 0.27 ns/op 18 | Benchmark_Int32Sub 2000000000 0.28 ns/op 19 | Benchmark_Int64Sub 2000000000 0.28 ns/op 20 | Benchmark_Float32Sub 2000000000 1.31 ns/op 21 | Benchmark_Float64Sub 2000000000 0.87 ns/op 22 | Benchmark_IntMul 2000000000 0.79 ns/op 23 | Benchmark_Int8Mul 2000000000 0.79 ns/op 24 | Benchmark_Int16Mul 2000000000 0.79 ns/op 25 | Benchmark_Int32Mul 2000000000 0.79 ns/op 26 | Benchmark_Int64Mul 2000000000 0.79 ns/op 27 | Benchmark_Float32Mul 2000000000 1.57 ns/op 28 | Benchmark_Float64Mul 2000000000 1.31 ns/op 29 | Benchmark_IntDiv 2000000000 1.57 ns/op 30 | Benchmark_Int8Div 2000000000 1.84 ns/op 31 | Benchmark_Int16Div 1000000000 2.08 ns/op 32 | Benchmark_Int32Div 2000000000 1.62 ns/op 33 | Benchmark_Int64Div 2000000000 1.57 ns/op 34 | Benchmark_Float32Div 50000000 44.3 ns/op 35 | Benchmark_Float64Div 50000000 48.0 ns/op 36 | ok labs05 49.453s 37 | 38 | 结论:浮点数除法明显更慢,尽量把除法转换为乘法运算。 -------------------------------------------------------------------------------- /labs04/labs04_test.go: -------------------------------------------------------------------------------- 1 | package labs04 2 | 3 | import "testing" 4 | 5 | type BigStruct struct { 6 | C01 int 7 | C02 int 8 | C03 int 9 | C04 int 10 | C05 int 11 | C06 int 12 | C07 int 13 | C08 int 14 | C09 int 15 | C10 int 16 | C11 int 17 | C12 int 18 | C13 int 19 | C14 int 20 | C15 int 21 | C16 int 22 | C17 int 23 | C18 int 24 | C19 int 25 | C20 int 26 | C21 int 27 | C22 int 28 | C23 int 29 | C24 int 30 | C25 int 31 | C26 int 32 | C27 int 33 | C28 int 34 | C29 int 35 | C30 int 36 | } 37 | 38 | func Loop1(a []*BigStruct) int { 39 | var n = 0 40 | 41 | for i := 0; i < len(a); i++ { 42 | n += a[i].C30 43 | } 44 | 45 | return n 46 | } 47 | 48 | func Loop2(a []*BigStruct) int { 49 | var n = 0 50 | 51 | for _, item := range a { 52 | n += item.C30 53 | } 54 | 55 | return n 56 | } 57 | 58 | func Loop3(a []BigStruct) int { 59 | var n = 0 60 | 61 | for i := 0; i < len(a); i++ { 62 | n += a[i].C30 63 | } 64 | 65 | return n 66 | } 67 | 68 | func Loop4(a []BigStruct) int { 69 | var n = 0 70 | 71 | for _, item := range a { 72 | n += item.C30 73 | } 74 | 75 | return n 76 | } 77 | 78 | func Benchmark_Loop1(b *testing.B) { 79 | b.StopTimer() 80 | var a = make([]*BigStruct, 1000) 81 | for i := 0; i < len(a); i++ { 82 | a[i] = new(BigStruct) 83 | } 84 | b.StartTimer() 85 | 86 | for i := 0; i < b.N; i++ { 87 | Loop1(a) 88 | } 89 | } 90 | 91 | func Benchmark_Loop2(b *testing.B) { 92 | b.StopTimer() 93 | var a = make([]*BigStruct, 1000) 94 | for i := 0; i < len(a); i++ { 95 | a[i] = new(BigStruct) 96 | } 97 | b.StartTimer() 98 | 99 | for i := 0; i < b.N; i++ { 100 | Loop2(a) 101 | } 102 | } 103 | 104 | func Benchmark_Loop3(b *testing.B) { 105 | b.StopTimer() 106 | var a = make([]BigStruct, 1000) 107 | b.StartTimer() 108 | 109 | for i := 0; i < b.N; i++ { 110 | Loop3(a) 111 | } 112 | } 113 | 114 | func Benchmark_Loop4(b *testing.B) { 115 | b.StopTimer() 116 | var a = make([]BigStruct, 1000) 117 | b.StartTimer() 118 | 119 | for i := 0; i < b.N; i++ { 120 | Loop4(a) 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /labs03/labs03_test.go: -------------------------------------------------------------------------------- 1 | package labs03 2 | 3 | import "testing" 4 | 5 | type BigStruct struct { 6 | C01 uint64 7 | C02 uint64 8 | C03 uint64 9 | C04 uint64 10 | C05 uint64 11 | C06 uint64 12 | C07 uint64 13 | C08 uint64 14 | C09 uint64 15 | C10 uint64 16 | C11 uint64 17 | C12 uint64 18 | C13 uint64 19 | C14 uint64 20 | C15 uint64 21 | C16 uint64 22 | C17 uint64 23 | C18 uint64 24 | C19 uint64 25 | C20 uint64 26 | C21 uint64 27 | C22 uint64 28 | C23 uint64 29 | C24 uint64 30 | C25 uint64 31 | C26 uint64 32 | C27 uint64 33 | C28 uint64 34 | C29 uint64 35 | C30 uint64 36 | } 37 | 38 | func NewStruct1() *BigStruct { 39 | return new(BigStruct) 40 | } 41 | 42 | func NewStruct2() *BigStruct { 43 | return &BigStruct{} 44 | } 45 | 46 | func NewStruct3() *BigStruct { 47 | var r = new(BigStruct) 48 | *r = BigStruct{} 49 | return r 50 | } 51 | 52 | func NewStruct4(r *BigStruct) { 53 | *r = BigStruct{} 54 | } 55 | 56 | func NewStruct5(r *BigStruct) { 57 | r.C01 = 0 58 | r.C02 = 0 59 | r.C03 = 0 60 | r.C04 = 0 61 | r.C05 = 0 62 | r.C06 = 0 63 | r.C07 = 0 64 | r.C08 = 0 65 | r.C09 = 0 66 | r.C10 = 0 67 | r.C11 = 0 68 | r.C12 = 0 69 | r.C13 = 0 70 | r.C14 = 0 71 | r.C15 = 0 72 | r.C16 = 0 73 | r.C17 = 0 74 | r.C18 = 0 75 | r.C19 = 0 76 | r.C20 = 0 77 | r.C21 = 0 78 | r.C22 = 0 79 | r.C23 = 0 80 | r.C24 = 0 81 | r.C25 = 0 82 | r.C26 = 0 83 | r.C27 = 0 84 | r.C28 = 0 85 | r.C29 = 0 86 | r.C30 = 0 87 | } 88 | 89 | func Benchmark_NewStruct1(b *testing.B) { 90 | for i := 0; i < b.N; i++ { 91 | NewStruct1() 92 | } 93 | } 94 | 95 | func Benchmark_NewStruct2(b *testing.B) { 96 | for i := 0; i < b.N; i++ { 97 | NewStruct2() 98 | } 99 | } 100 | 101 | func Benchmark_NewStruct3(b *testing.B) { 102 | for i := 0; i < b.N; i++ { 103 | NewStruct3() 104 | } 105 | } 106 | 107 | func Benchmark_NewStruct4(b *testing.B) { 108 | var r = new(BigStruct) 109 | 110 | for i := 0; i < b.N; i++ { 111 | NewStruct4(r) 112 | } 113 | } 114 | 115 | func Benchmark_NewStruct5(b *testing.B) { 116 | var r = new(BigStruct) 117 | 118 | for i := 0; i < b.N; i++ { 119 | NewStruct5(r) 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /labs11/labs11.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | import "encoding/json" 5 | 6 | type M struct { 7 | AA *A 8 | BB []*A 9 | CC []*A 10 | DD []*A 11 | EE map[string]*A 12 | } 13 | 14 | type A struct { 15 | X int 16 | Y int 17 | Z int 18 | Next *A 19 | } 20 | 21 | func main() { 22 | var m = &M{ 23 | AA: &A{ 24 | X: 1, Y: 2, Z: 3, Next: &A{ 25 | X: 10, Y: 20, Z: 30, Next: &A{ 26 | X: 100, Y: 200, Z: 300, 27 | }, 28 | }, 29 | }, 30 | BB: []*A{ 31 | &A{X: 1, Y: 2, Z: 3}, 32 | &A{X: 10, Y: 20, Z: 30}, 33 | &A{X: 100, Y: 200, Z: 300}, 34 | }, 35 | CC: []*A{ 36 | &A{ 37 | X: 1, Y: 2, Z: 3, Next: &A{ 38 | X: 10, Y: 20, Z: 30, Next: &A{ 39 | X: 100, Y: 200, Z: 300, 40 | }, 41 | }, 42 | }, 43 | &A{ 44 | X: 4, Y: 5, Z: 6, Next: &A{ 45 | X: 40, Y: 50, Z: 60, Next: &A{ 46 | X: 400, Y: 500, Z: 600, 47 | }, 48 | }, 49 | }, 50 | &A{ 51 | X: 7, Y: 8, Z: 9, Next: &A{ 52 | X: 70, Y: 80, Z: 90, Next: &A{ 53 | X: 700, Y: 800, Z: 900, 54 | }, 55 | }, 56 | }, 57 | }, 58 | DD: make([]*A, 3), 59 | EE: map[string]*A{ 60 | "A": &A{X: 1, Y: 2, Z: 3}, 61 | "B": &A{X: 10, Y: 20, Z: 30}, 62 | "C": &A{X: 100, Y: 200, Z: 300}, 63 | }, 64 | } 65 | 66 | var j, err = json.Marshal(m) 67 | 68 | if err != nil { 69 | fmt.Println(err) 70 | } 71 | 72 | fmt.Printf("%s\n", j) 73 | 74 | var b = new(M) 75 | 76 | var err2 = json.Unmarshal(j, b) 77 | 78 | if err2 != nil { 79 | fmt.Println(err2) 80 | } 81 | 82 | fmt.Println("\n[M.AA]") 83 | 84 | for a := b.AA; a != nil; a = a.Next { 85 | fmt.Printf("%p -> %+v\n", a, *a) 86 | } 87 | 88 | fmt.Println("\n[M.BB]") 89 | 90 | for i, a := range b.BB { 91 | fmt.Printf("%d -> %+v\n", i, *a) 92 | } 93 | 94 | fmt.Println("\n[M.CC]") 95 | 96 | for i, a := range b.CC { 97 | fmt.Printf("%d ->\n", i) 98 | for aa := a; aa != nil; aa = aa.Next { 99 | fmt.Printf(" %p -> %+v\n", aa, *aa) 100 | } 101 | } 102 | 103 | fmt.Println("\n[M.DD]") 104 | 105 | for i, a := range b.DD { 106 | fmt.Printf("%d -> %v\n", i, a) 107 | } 108 | 109 | fmt.Println("\n[M.EE]") 110 | 111 | for i, a := range b.EE { 112 | fmt.Printf("%s -> %+v\n", i, *a) 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /labs06/labs06_test.go: -------------------------------------------------------------------------------- 1 | package labs06 2 | 3 | import "testing" 4 | 5 | type BigStruct struct { 6 | C01 int 7 | C02 int 8 | C03 int 9 | C04 int 10 | C05 int 11 | C06 int 12 | C07 int 13 | C08 int 14 | C09 int 15 | C10 int 16 | C11 int 17 | C12 int 18 | C13 int 19 | C14 int 20 | C15 int 21 | C16 int 22 | C17 int 23 | C18 int 24 | C19 int 25 | C20 int 26 | C21 int 27 | C22 int 28 | C23 int 29 | C24 int 30 | C25 int 31 | C26 int 32 | C27 int 33 | C28 int 34 | C29 int 35 | C30 int 36 | } 37 | 38 | func Loop1(a []BigStruct) int { 39 | for i := 0; i < len(a); i++ { 40 | if a[i].C30 == 3 { 41 | return i 42 | } 43 | } 44 | 45 | return -1 46 | } 47 | 48 | func Loop2(a []BigStruct) int { 49 | for i := len(a) - 1; i >= 0; i-- { 50 | if a[i].C30 == 1 { 51 | return i 52 | } 53 | } 54 | 55 | return -1 56 | } 57 | 58 | func Loop3(a map[int]BigStruct) int { 59 | return a[2].C30 60 | } 61 | 62 | func Loop4(a []*BigStruct) int { 63 | for i, x := range a { 64 | if x.C30 == 3 { 65 | return i 66 | } 67 | } 68 | 69 | return -1 70 | } 71 | 72 | func Loop5(a []BigStruct) int { 73 | switch { 74 | case a[0].C01 == 3: 75 | return 0 76 | case a[1].C01 == 3: 77 | return 1 78 | case a[2].C01 == 3: 79 | return 2 80 | } 81 | 82 | return -1 83 | } 84 | 85 | func Benchmark_Loop1(b *testing.B) { 86 | var a = make([]BigStruct, 3) 87 | 88 | a[0].C30 = 1 89 | a[1].C30 = 2 90 | a[2].C30 = 3 91 | 92 | for i := 0; i < b.N; i++ { 93 | Loop1(a) 94 | } 95 | } 96 | 97 | func Benchmark_Loop2(b *testing.B) { 98 | var a = make([]BigStruct, 3) 99 | 100 | a[0].C30 = 1 101 | a[1].C30 = 2 102 | a[2].C30 = 3 103 | 104 | for i := 0; i < b.N; i++ { 105 | Loop2(a) 106 | } 107 | } 108 | 109 | func Benchmark_Loop3(b *testing.B) { 110 | var a = make(map[int]BigStruct, 3) 111 | 112 | a[0] = BigStruct{C30: 1} 113 | a[1] = BigStruct{C30: 2} 114 | a[2] = BigStruct{C30: 3} 115 | 116 | for i := 0; i < b.N; i++ { 117 | Loop3(a) 118 | } 119 | } 120 | 121 | func Benchmark_Loop4(b *testing.B) { 122 | var a = make([]*BigStruct, 3) 123 | 124 | a[0] = &BigStruct{C30: 1} 125 | a[1] = &BigStruct{C30: 2} 126 | a[2] = &BigStruct{C30: 3} 127 | 128 | for i := 0; i < b.N; i++ { 129 | Loop4(a) 130 | } 131 | } 132 | 133 | func Benchmark_Loop5(b *testing.B) { 134 | var a = make([]BigStruct, 3) 135 | 136 | a[0].C30 = 1 137 | a[1].C30 = 2 138 | a[2].C30 = 3 139 | 140 | for i := 0; i < b.N; i++ { 141 | Loop5(a) 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /labs08/labs08_test.go: -------------------------------------------------------------------------------- 1 | package labs08 2 | 3 | import "testing" 4 | import "reflect" 5 | 6 | var data []*BigStruct 7 | 8 | func init() { 9 | data = make([]*BigStruct, 1000) 10 | 11 | for i := 0; i < len(data); i++ { 12 | data[i] = new(BigStruct) 13 | } 14 | 15 | data[len(data)-1].C30 = 88888888 16 | } 17 | 18 | func Loop1() *BigStruct { 19 | for _, n := range data { 20 | if n.C30 == 88888888 { 21 | return n 22 | } 23 | } 24 | 25 | return nil 26 | } 27 | 28 | func Loop2(callback func(*BigStruct) bool) *BigStruct { 29 | for _, n := range data { 30 | if callback(n) { 31 | return n 32 | } 33 | } 34 | 35 | return nil 36 | } 37 | 38 | func Loop3(callback func(BigStruct) bool) *BigStruct { 39 | for _, n := range data { 40 | if callback(*n) { 41 | return n 42 | } 43 | } 44 | 45 | return nil 46 | } 47 | 48 | func Loop4(callback func(*BigStruct) bool) *BigStruct { 49 | for _, n := range data { 50 | nn := *n 51 | if callback(&nn) { 52 | return n 53 | } 54 | } 55 | 56 | return nil 57 | } 58 | 59 | func Loop5(name string, value interface{}) *BigStruct { 60 | for _, n := range data { 61 | var v = reflect.ValueOf(n) 62 | 63 | if reflect.DeepEqual(v.Elem().FieldByName(name).Interface(), value) { 64 | return n 65 | } 66 | } 67 | 68 | return nil 69 | } 70 | 71 | func Loop6(query *Query) *BigStruct { 72 | for _, n := range data { 73 | if query.Match(n) { 74 | var nn = *n 75 | return &nn 76 | } 77 | } 78 | return nil 79 | } 80 | 81 | // 基准测试 82 | // 83 | func Benchmark_Loop1(b *testing.B) { 84 | for i := 0; i < b.N; i++ { 85 | Loop1() 86 | } 87 | } 88 | 89 | // 测试指针传递进行查找的效率(外部可修改内部数据) 90 | // 91 | func Benchmark_Loop2(b *testing.B) { 92 | for i := 0; i < b.N; i++ { 93 | Loop2(func(n *BigStruct) bool { 94 | return n.C30 == 88888888 95 | }) 96 | } 97 | } 98 | 99 | // 测试值传递进行查找的效率(外部不可修改内部数据) 100 | // 101 | func Benchmark_Loop3(b *testing.B) { 102 | for i := 0; i < b.N; i++ { 103 | Loop3(func(n BigStruct) bool { 104 | return n.C30 == 88888888 105 | }) 106 | } 107 | } 108 | 109 | // 测试复制数据后传递指针进行查找的效率(外部不可修改内部数据) 110 | // 111 | func Benchmark_Loop4(b *testing.B) { 112 | for i := 0; i < b.N; i++ { 113 | Loop4(func(n *BigStruct) bool { 114 | return n.C30 == 88888888 115 | }) 116 | } 117 | } 118 | 119 | // 测试反射取值(自定义查询表达式的可能性) 120 | // 121 | func Benchmark_Loop5(b *testing.B) { 122 | for i := 0; i < b.N; i++ { 123 | Loop5("C30", 88888888) 124 | } 125 | } 126 | 127 | // 测试指针取值(自定义查询表达式的可能性) 128 | // 129 | func Benchmark_Loop6(b *testing.B) { 130 | var query = NewQuery("C30", "==", 88888888) 131 | 132 | for i := 0; i < b.N; i++ { 133 | Loop6(query) 134 | } 135 | } 136 | 137 | func Test_Loop4(t *testing.T) { 138 | var a = new(BigStruct) 139 | a.C30 = 100 140 | 141 | var b = *a 142 | var c = &b 143 | 144 | c.C30 = 200 145 | 146 | if a.C30 == c.C30 { 147 | t.Fail() 148 | } 149 | 150 | if b.C30 != c.C30 { 151 | t.Fail() 152 | } 153 | } 154 | 155 | func Test_Loop5(t *testing.T) { 156 | if Loop5("C30", 88888888) == nil { 157 | t.Fail() 158 | } 159 | } 160 | 161 | func Test_Loop6(t *testing.T) { 162 | var query = NewQuery("C30", "==", 88888888) 163 | 164 | if Loop6(query) == nil { 165 | t.Fail() 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /labs07/labs07_test.go: -------------------------------------------------------------------------------- 1 | package labs07 2 | 3 | import "testing" 4 | import "reflect" 5 | 6 | var data *BigStruct = &BigStruct{C30: 88888888} 7 | 8 | func init() { 9 | for i := 0; i < 1000; i++ { 10 | var newData = new(BigStruct) 11 | newData.C30 = i 12 | newData.next = data 13 | data = newData 14 | } 15 | } 16 | 17 | func Loop1() *BigStruct { 18 | for n := data; n != nil; n = n.next { 19 | if n.C30 == 88888888 { 20 | return n 21 | } 22 | } 23 | 24 | return nil 25 | } 26 | 27 | func Loop2(callback func(*BigStruct) bool) *BigStruct { 28 | for n := data; n != nil; n = n.next { 29 | if callback(n) { 30 | return n 31 | } 32 | } 33 | 34 | return nil 35 | } 36 | 37 | func Loop3(callback func(BigStruct) bool) *BigStruct { 38 | for n := data; n != nil; n = n.next { 39 | if callback(*n) { 40 | return n 41 | } 42 | } 43 | 44 | return nil 45 | } 46 | 47 | func Loop4(callback func(*BigStruct) bool) *BigStruct { 48 | for n := data; n != nil; n = n.next { 49 | nn := *n 50 | if callback(&nn) { 51 | return n 52 | } 53 | } 54 | 55 | return nil 56 | } 57 | 58 | func Loop5(name string, value interface{}) *BigStruct { 59 | for n := data; n != nil; n = n.next { 60 | var v = reflect.ValueOf(n) 61 | 62 | if reflect.DeepEqual(v.Elem().FieldByName(name).Interface(), value) { 63 | return n 64 | } 65 | } 66 | 67 | return nil 68 | } 69 | 70 | func Loop6(query *Query) *BigStruct { 71 | for n := data; n != nil; n = n.next { 72 | if query.Match(n) { 73 | var nn = *n 74 | return &nn 75 | } 76 | } 77 | return nil 78 | } 79 | 80 | // 基准测试 81 | // 82 | func Benchmark_Loop1(b *testing.B) { 83 | for i := 0; i < b.N; i++ { 84 | Loop1() 85 | } 86 | } 87 | 88 | // 测试指针传递进行查找的效率(外部可修改内部数据) 89 | // 90 | func Benchmark_Loop2(b *testing.B) { 91 | for i := 0; i < b.N; i++ { 92 | Loop2(func(n *BigStruct) bool { 93 | return n.C30 == 88888888 94 | }) 95 | } 96 | } 97 | 98 | // 测试值传递进行查找的效率(外部不可修改内部数据) 99 | // 100 | func Benchmark_Loop3(b *testing.B) { 101 | for i := 0; i < b.N; i++ { 102 | Loop3(func(n BigStruct) bool { 103 | return n.C30 == 88888888 104 | }) 105 | } 106 | } 107 | 108 | // 测试复制数据后传递指针进行查找的效率(外部不可修改内部数据) 109 | // 110 | func Benchmark_Loop4(b *testing.B) { 111 | for i := 0; i < b.N; i++ { 112 | Loop4(func(n *BigStruct) bool { 113 | return n.C30 == 88888888 114 | }) 115 | } 116 | } 117 | 118 | // 测试反射取值(自定义查询表达式的可能性) 119 | // 120 | func Benchmark_Loop5(b *testing.B) { 121 | for i := 0; i < b.N; i++ { 122 | Loop5("C30", 88888888) 123 | } 124 | } 125 | 126 | // 测试指针取值(自定义查询表达式的可能性) 127 | // 128 | func Benchmark_Loop6(b *testing.B) { 129 | var query = NewQuery("C30", "==", 88888888) 130 | 131 | for i := 0; i < b.N; i++ { 132 | Loop6(query) 133 | } 134 | } 135 | 136 | // 测试指针取值(自定义查询表达式的可能性) 137 | // 138 | func Benchmark_Loop7(b *testing.B) { 139 | for i := 0; i < b.N; i++ { 140 | var query = NewQuery("C30", "==", 88888888) 141 | 142 | Loop6(query) 143 | } 144 | } 145 | 146 | func Test_Loop4(t *testing.T) { 147 | var a = new(BigStruct) 148 | a.C30 = 100 149 | 150 | var b = *a 151 | var c = &b 152 | 153 | c.C30 = 200 154 | 155 | if a.C30 == c.C30 { 156 | t.Fail() 157 | } 158 | 159 | if b.C30 != c.C30 { 160 | t.Fail() 161 | } 162 | } 163 | 164 | func Test_Loop5(t *testing.T) { 165 | if Loop5("C30", 88888888) == nil { 166 | t.Fail() 167 | } 168 | } 169 | 170 | func Test_Loop6(t *testing.T) { 171 | var query = NewQuery("C30", "==", 88888888) 172 | 173 | if Loop6(query) == nil { 174 | t.Fail() 175 | } 176 | } 177 | -------------------------------------------------------------------------------- /labs14/cgo_copy.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | /* 4 | #include 5 | */ 6 | import "C" 7 | import "time" 8 | import "reflect" 9 | import "unsafe" 10 | 11 | type BigStruct struct { 12 | C01 int 13 | C02 int 14 | C03 int 15 | C04 int 16 | C05 int 17 | C06 int 18 | C07 int 19 | C08 int 20 | C09 int 21 | C10 int 22 | C11 int 23 | C12 int 24 | C13 int 25 | C14 int 26 | C15 int 27 | C16 int 28 | C17 int 29 | C18 int 30 | C19 int 31 | C20 int 32 | C21 int 33 | C22 int 34 | C23 int 35 | C24 int 36 | C25 int 37 | C26 int 38 | C27 int 39 | C28 int 40 | C29 int 41 | C30 int 42 | } 43 | 44 | func initTestData() []BigStruct { 45 | data := make([]BigStruct, 1000) 46 | for i := 0; i < len(data); i++ { 47 | n := i * 30 48 | data[i] = BigStruct{ 49 | C01: n + 1, 50 | C02: n + 2, 51 | C03: n + 3, 52 | C04: n + 4, 53 | C05: n + 5, 54 | C06: n + 6, 55 | C07: n + 7, 56 | C08: n + 8, 57 | C09: n + 9, 58 | C10: n + 10, 59 | C11: n + 11, 60 | C12: n + 12, 61 | C13: n + 13, 62 | C14: n + 14, 63 | C15: n + 15, 64 | C16: n + 16, 65 | C17: n + 17, 66 | C18: n + 18, 67 | C19: n + 19, 68 | C20: n + 20, 69 | C21: n + 21, 70 | C22: n + 22, 71 | C23: n + 23, 72 | C24: n + 24, 73 | C25: n + 25, 74 | C26: n + 26, 75 | C27: n + 27, 76 | C28: n + 28, 77 | C29: n + 29, 78 | C30: n + 30, 79 | } 80 | } 81 | return data 82 | } 83 | 84 | func checkTestData(length int, data []BigStruct) { 85 | assert(len(data) == length) 86 | for i := 0; i < len(data); i++ { 87 | n := i * 30 88 | assert(data[i].C01 == n+1) 89 | assert(data[i].C02 == n+2) 90 | assert(data[i].C03 == n+3) 91 | assert(data[i].C04 == n+4) 92 | assert(data[i].C05 == n+5) 93 | assert(data[i].C06 == n+6) 94 | assert(data[i].C07 == n+7) 95 | assert(data[i].C08 == n+8) 96 | assert(data[i].C09 == n+9) 97 | assert(data[i].C10 == n+10) 98 | assert(data[i].C11 == n+11) 99 | assert(data[i].C12 == n+12) 100 | assert(data[i].C13 == n+13) 101 | assert(data[i].C14 == n+14) 102 | assert(data[i].C15 == n+15) 103 | assert(data[i].C16 == n+16) 104 | assert(data[i].C17 == n+17) 105 | assert(data[i].C18 == n+18) 106 | assert(data[i].C19 == n+19) 107 | assert(data[i].C20 == n+20) 108 | assert(data[i].C21 == n+21) 109 | assert(data[i].C22 == n+22) 110 | assert(data[i].C23 == n+23) 111 | assert(data[i].C24 == n+24) 112 | assert(data[i].C25 == n+25) 113 | assert(data[i].C26 == n+26) 114 | assert(data[i].C27 == n+27) 115 | assert(data[i].C28 == n+28) 116 | assert(data[i].C29 == n+29) 117 | assert(data[i].C30 == n+30) 118 | } 119 | } 120 | 121 | func assert(c bool) { 122 | if !c { 123 | panic("assert failed") 124 | } 125 | } 126 | 127 | func main() { 128 | data1 := initTestData() 129 | 130 | checkTestData(len(data1), data1) 131 | 132 | itemSize := unsafe.Sizeof(BigStruct{}) 133 | 134 | csize := C.size_t(itemSize * uintptr(len(data1))) 135 | 136 | t1 := time.Now().Nanosecond() 137 | 138 | mem := C.malloc(csize) 139 | 140 | C.memcpy(mem, unsafe.Pointer((*reflect.SliceHeader)(unsafe.Pointer(&data1)).Data), csize) 141 | 142 | t2 := time.Now().Nanosecond() 143 | 144 | println("Go to C:", (t2-t1)/int(time.Microsecond)) 145 | 146 | data2 := new(reflect.SliceHeader) 147 | data2.Cap = len(data1) 148 | data2.Len = len(data1) 149 | data2.Data = uintptr(mem) 150 | 151 | checkTestData(len(data1), *(*[]BigStruct)(unsafe.Pointer(data2))) 152 | 153 | t3 := time.Now().Nanosecond() 154 | 155 | data3 := make([]BigStruct, len(data1)) 156 | copy(data3, *(*[]BigStruct)(unsafe.Pointer(data2))) 157 | 158 | t4 := time.Now().Nanosecond() 159 | 160 | checkTestData(len(data1), data3) 161 | 162 | println("C to Go:", (t4-t3)/int(time.Microsecond)) 163 | } 164 | -------------------------------------------------------------------------------- /labs30/labs30.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type TransLog interface { 6 | Commit(*Database) 7 | Rollback(*Database) 8 | } 9 | 10 | type Database struct { 11 | transLogs []TransLog 12 | playerItem map[int]*PlayerItem 13 | } 14 | 15 | type PlayerItem struct { 16 | Id int 17 | ItemId int 18 | Num int 19 | } 20 | 21 | func NewDatabase() *Database { 22 | return &Database{ 23 | playerItem: make(map[int]*PlayerItem), 24 | } 25 | } 26 | 27 | func (db *Database) Transaction(trans func()) { 28 | defer func() { 29 | if err := recover(); err != nil { 30 | for i := len(db.transLogs) - 1; i >= 0; i-- { 31 | db.transLogs[i].Rollback(db) 32 | } 33 | panic(err) 34 | } else { 35 | for _, tl := range db.transLogs { 36 | tl.Commit(db) 37 | } 38 | } 39 | db.transLogs = db.transLogs[0:0] 40 | }() 41 | trans() 42 | } 43 | 44 | func (db *Database) LookupPlayerItem(id int) *PlayerItem { 45 | return db.playerItem[id] 46 | } 47 | 48 | func (db *Database) InsertPlayerItem(playerItem *PlayerItem) { 49 | db.playerItem[playerItem.Id] = playerItem 50 | db.transLogs = append(db.transLogs, &PlayerItemTransLog{ 51 | Type: INSERT, New: playerItem, 52 | }) 53 | } 54 | 55 | func (db *Database) DeletePlayerItem(playerItem *PlayerItem) { 56 | old := db.playerItem[playerItem.Id] 57 | delete(db.playerItem, playerItem.Id) 58 | db.transLogs = append(db.transLogs, &PlayerItemTransLog{ 59 | Type: DELETE, Old: old, 60 | }) 61 | } 62 | 63 | func (db *Database) UpdatePlayerItem(playerItem *PlayerItem) { 64 | old := db.playerItem[playerItem.Id] 65 | db.playerItem[playerItem.Id] = playerItem 66 | db.transLogs = append(db.transLogs, &PlayerItemTransLog{ 67 | Type: UPDATE, Old: old, New: playerItem, 68 | }) 69 | } 70 | 71 | type TransType int 72 | 73 | const ( 74 | INSERT TransType = iota 75 | DELETE 76 | UPDATE 77 | ) 78 | 79 | type PlayerItemTransLog struct { 80 | Type TransType 81 | Old *PlayerItem 82 | New *PlayerItem 83 | } 84 | 85 | func (transLog *PlayerItemTransLog) Commit(db *Database) { 86 | switch transLog.Type { 87 | case INSERT: 88 | fmt.Printf( 89 | "INSERT INTO player_item (id, item_id, num) VALUES (%d, %d, %d)\n", 90 | transLog.New.Id, transLog.New.ItemId, transLog.New.Num, 91 | ) 92 | case DELETE: 93 | fmt.Printf( 94 | "DELETE player_item WHERE id = %d\n", 95 | transLog.Old.Id, 96 | ) 97 | case UPDATE: 98 | fmt.Printf( 99 | "UPDATE player_item SET id = %d, item_id = %d, num = %d\n", 100 | transLog.New.Id, transLog.New.ItemId, transLog.New.Num, 101 | ) 102 | } 103 | } 104 | 105 | func (transLog *PlayerItemTransLog) Rollback(db *Database) { 106 | switch transLog.Type { 107 | case INSERT: 108 | delete(db.playerItem, transLog.New.Id) 109 | case DELETE: 110 | db.playerItem[transLog.Old.Id] = transLog.Old 111 | case UPDATE: 112 | db.playerItem[transLog.Old.Id] = transLog.Old 113 | } 114 | } 115 | 116 | func main() { 117 | db := NewDatabase() 118 | 119 | db.Transaction(func() { 120 | db.InsertPlayerItem(&PlayerItem{ 121 | Id: 1, 122 | ItemId: 100, 123 | Num: 1, 124 | }) 125 | db.InsertPlayerItem(&PlayerItem{ 126 | Id: 2, 127 | ItemId: 100, 128 | Num: 1, 129 | }) 130 | }) 131 | 132 | fmt.Println(db.playerItem) 133 | fmt.Println() 134 | 135 | db.Transaction(func() { 136 | item := db.LookupPlayerItem(1) 137 | db.DeletePlayerItem(item) 138 | }) 139 | 140 | fmt.Println(db.playerItem) 141 | fmt.Println() 142 | 143 | func() { 144 | defer func() { 145 | recover() 146 | fmt.Println("rollback") 147 | }() 148 | 149 | db.Transaction(func() { 150 | item := db.LookupPlayerItem(2) 151 | db.DeletePlayerItem(item) 152 | panic("error") 153 | }) 154 | }() 155 | 156 | fmt.Println(db.playerItem) 157 | fmt.Println() 158 | } 159 | -------------------------------------------------------------------------------- /labs19/normal.go: -------------------------------------------------------------------------------- 1 | package labs19 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "reflect" 7 | "strconv" 8 | "unsafe" 9 | ) 10 | 11 | func Verify(data interface{}) error { 12 | typeOfData := reflect.TypeOf(data) 13 | valueOfData := reflect.ValueOf(data) 14 | 15 | if typeOfData.Kind() == reflect.Ptr { 16 | typeOfData = typeOfData.Elem() 17 | valueOfData = valueOfData.Elem() 18 | } 19 | 20 | numField := typeOfData.NumField() 21 | 22 | for i := 0; i < numField; i++ { 23 | fieldInfo := typeOfData.Field(i) 24 | 25 | if fieldInfo.Type.Kind() == reflect.String { 26 | maxLength := fieldInfo.Tag.Get("max-length") 27 | 28 | if maxLength != "" { 29 | maxLength2, _ := strconv.Atoi(maxLength) 30 | if valueOfData.Field(i).Len() > maxLength2 { 31 | return errors.New(fmt.Sprintf("len(%s.%s) > %s", typeOfData.Name(), fieldInfo.Name, maxLength)) 32 | } 33 | } 34 | } 35 | } 36 | 37 | return nil 38 | } 39 | 40 | var cache = make(map[reflect.Type][]func(reflect.Value) error) 41 | 42 | func FastVerify(data interface{}) error { 43 | typeOfData := reflect.TypeOf(data) 44 | valueOfData := reflect.ValueOf(data) 45 | 46 | if typeOfData.Kind() == reflect.Ptr { 47 | typeOfData = typeOfData.Elem() 48 | valueOfData = valueOfData.Elem() 49 | } 50 | 51 | verifyCallbacks, cached := cache[typeOfData] 52 | 53 | if !cached { 54 | numField := typeOfData.NumField() 55 | 56 | for i := 0; i < numField; i++ { 57 | fieldInfo := typeOfData.Field(i) 58 | 59 | if fieldInfo.Type.Kind() == reflect.String { 60 | maxLength := fieldInfo.Tag.Get("max-length") 61 | 62 | if maxLength != "" { 63 | var ( 64 | maxLength2, _ = strconv.Atoi(maxLength) 65 | errorMessage = fmt.Sprintf("len(%s.%s) > %s", typeOfData.Name(), fieldInfo.Name, maxLength) 66 | fieldIndex = i 67 | ) 68 | verifyCallbacks = append(verifyCallbacks, func(v reflect.Value) error { 69 | if v.Field(fieldIndex).Len() > maxLength2 { 70 | return errors.New(errorMessage) 71 | } 72 | return nil 73 | }) 74 | } 75 | } 76 | } 77 | 78 | cache[typeOfData] = verifyCallbacks 79 | } 80 | 81 | for _, callback := range verifyCallbacks { 82 | if err := callback(valueOfData); err != nil { 83 | return err 84 | } 85 | } 86 | 87 | return nil 88 | } 89 | 90 | var cache2 = make(map[reflect.Type][]func(uintptr) error) 91 | 92 | func VeryFastVerify(data interface{}) error { 93 | typeOfData := reflect.TypeOf(data) 94 | valueOfData := reflect.ValueOf(data) 95 | 96 | if typeOfData.Kind() == reflect.Ptr { 97 | typeOfData = typeOfData.Elem() 98 | valueOfData = valueOfData.Elem() 99 | } 100 | 101 | verifyCallbacks, cached := cache2[typeOfData] 102 | 103 | if !cached { 104 | beginAddr := valueOfData.UnsafeAddr() 105 | numField := typeOfData.NumField() 106 | 107 | for i := 0; i < numField; i++ { 108 | fieldInfo := typeOfData.Field(i) 109 | 110 | if fieldInfo.Type.Kind() == reflect.String { 111 | maxLength := fieldInfo.Tag.Get("max-length") 112 | 113 | if maxLength != "" { 114 | var ( 115 | maxLength2, _ = strconv.Atoi(maxLength) 116 | errorMessage = fmt.Sprintf("len(%s.%s) > %s", typeOfData.Name(), fieldInfo.Name, maxLength) 117 | fieldOffset = valueOfData.Field(i).UnsafeAddr() - beginAddr 118 | ) 119 | verifyCallbacks = append(verifyCallbacks, func(ptr uintptr) error { 120 | if (*reflect.StringHeader)(unsafe.Pointer(ptr+fieldOffset)).Len > maxLength2 { 121 | return errors.New(errorMessage) 122 | } 123 | return nil 124 | }) 125 | } 126 | } 127 | } 128 | 129 | cache2[typeOfData] = verifyCallbacks 130 | } 131 | 132 | addr := valueOfData.UnsafeAddr() 133 | 134 | for _, callback := range verifyCallbacks { 135 | if err := callback(addr); err != nil { 136 | return err 137 | } 138 | } 139 | 140 | return nil 141 | } 142 | -------------------------------------------------------------------------------- /labs05/labs05_test.go: -------------------------------------------------------------------------------- 1 | package labs05 2 | 3 | import "testing" 4 | 5 | func Benchmark_IntAdd(b *testing.B) { 6 | var a = 0 7 | 8 | for i := 0; i < b.N; i++ { 9 | a += 1 10 | } 11 | } 12 | 13 | func Benchmark_Int8Add(b *testing.B) { 14 | var a int8 = 0 15 | 16 | for i := 0; i < b.N; i++ { 17 | a += 1 18 | } 19 | } 20 | 21 | func Benchmark_Int16Add(b *testing.B) { 22 | var a int8 = 0 23 | 24 | for i := 0; i < b.N; i++ { 25 | a += 1 26 | } 27 | } 28 | 29 | func Benchmark_Int32Add(b *testing.B) { 30 | var a int32 = 0 31 | 32 | for i := 0; i < b.N; i++ { 33 | a += 1 34 | } 35 | } 36 | 37 | func Benchmark_Int64Add(b *testing.B) { 38 | var a int64 = 0 39 | 40 | for i := 0; i < b.N; i++ { 41 | a += 1 42 | } 43 | } 44 | 45 | func Benchmark_Float32Add(b *testing.B) { 46 | var a float32 = 0.1 47 | 48 | for i := 0; i < b.N; i++ { 49 | a += 1.0 50 | } 51 | } 52 | 53 | func Benchmark_Float64Add(b *testing.B) { 54 | var a float64 = 0.1 55 | 56 | for i := 0; i < b.N; i++ { 57 | a += 1.0 58 | } 59 | } 60 | 61 | func Benchmark_IntSub(b *testing.B) { 62 | var a = 0x7FFFFFFFFF 63 | 64 | for i := 0; i < b.N; i++ { 65 | a -= 1 66 | } 67 | } 68 | 69 | func Benchmark_Int8Sub(b *testing.B) { 70 | var a int8 = 0x7F 71 | 72 | for i := 0; i < b.N; i++ { 73 | a -= 1 74 | } 75 | } 76 | 77 | func Benchmark_Int16Sub(b *testing.B) { 78 | var a int16 = 0x7FFF 79 | 80 | for i := 0; i < b.N; i++ { 81 | a -= 1 82 | } 83 | } 84 | 85 | func Benchmark_Int32Sub(b *testing.B) { 86 | var a int32 = 0x7FFFFFFF 87 | 88 | for i := 0; i < b.N; i++ { 89 | a -= 1 90 | } 91 | } 92 | 93 | func Benchmark_Int64Sub(b *testing.B) { 94 | var a int64 = 0x7FFFFFFFFF 95 | 96 | for i := 0; i < b.N; i++ { 97 | a -= 1 98 | } 99 | } 100 | 101 | func Benchmark_Float32Sub(b *testing.B) { 102 | var a = float32(0x7FFFFFFF) 103 | 104 | for i := 0; i < b.N; i++ { 105 | a -= 1.0 106 | } 107 | } 108 | 109 | func Benchmark_Float64Sub(b *testing.B) { 110 | var a = float64(0xFFFFFFFFFF) 111 | 112 | for i := 0; i < b.N; i++ { 113 | a -= 1.0 114 | } 115 | } 116 | 117 | func Benchmark_IntMul(b *testing.B) { 118 | var a = 1 119 | 120 | for i := 0; i < b.N; i++ { 121 | a *= 3 122 | } 123 | } 124 | 125 | func Benchmark_Int8Mul(b *testing.B) { 126 | var a int8 = 1 127 | 128 | for i := 0; i < b.N; i++ { 129 | a *= 3 130 | } 131 | } 132 | 133 | func Benchmark_Int16Mul(b *testing.B) { 134 | var a int16 = 1 135 | 136 | for i := 0; i < b.N; i++ { 137 | a *= 3 138 | } 139 | } 140 | 141 | func Benchmark_Int32Mul(b *testing.B) { 142 | var a int32 = 1 143 | 144 | for i := 0; i < b.N; i++ { 145 | a *= 3 146 | } 147 | } 148 | 149 | func Benchmark_Int64Mul(b *testing.B) { 150 | var a int64 = 1 151 | 152 | for i := 0; i < b.N; i++ { 153 | a *= 3 154 | } 155 | } 156 | 157 | func Benchmark_Float32Mul(b *testing.B) { 158 | var a float32 = 1.0 159 | 160 | for i := 0; i < b.N; i++ { 161 | a *= 1.5 162 | } 163 | } 164 | 165 | func Benchmark_Float64Mul(b *testing.B) { 166 | var a float64 = 1.0 167 | 168 | for i := 0; i < b.N; i++ { 169 | a *= 1.5 170 | } 171 | } 172 | 173 | func Benchmark_IntDiv(b *testing.B) { 174 | var a = 0x7FFFFFFFFF 175 | 176 | for i := 0; i < b.N; i++ { 177 | a /= 3 178 | } 179 | } 180 | 181 | func Benchmark_Int8Div(b *testing.B) { 182 | var a int8 = 0x7F 183 | 184 | for i := 0; i < b.N; i++ { 185 | a /= 3 186 | } 187 | } 188 | 189 | func Benchmark_Int16Div(b *testing.B) { 190 | var a int16 = 0x7FFF 191 | 192 | for i := 0; i < b.N; i++ { 193 | a /= 3 194 | } 195 | } 196 | 197 | func Benchmark_Int32Div(b *testing.B) { 198 | var a int32 = 0x7FFFFFFF 199 | 200 | for i := 0; i < b.N; i++ { 201 | a /= 3 202 | } 203 | } 204 | 205 | func Benchmark_Int64Div(b *testing.B) { 206 | var a int64 = 0x7FFFFFFFFF 207 | 208 | for i := 0; i < b.N; i++ { 209 | a /= 3 210 | } 211 | } 212 | 213 | func Benchmark_Float32Div(b *testing.B) { 214 | var a = float32(0x7FFFFFFF) 215 | 216 | for i := 0; i < b.N; i++ { 217 | a /= 1.5 218 | } 219 | } 220 | 221 | func Benchmark_Float64Div(b *testing.B) { 222 | var a = float64(0x7FFFFFFFFF) 223 | 224 | for i := 0; i < b.N; i++ { 225 | a /= 1.5 226 | } 227 | } 228 | -------------------------------------------------------------------------------- /labs31/labs31_test.go: -------------------------------------------------------------------------------- 1 | package labs31 2 | 3 | import ( 4 | "math/rand" 5 | "sort" 6 | "testing" 7 | "time" 8 | ) 9 | 10 | var benchx int 11 | 12 | func init() { 13 | rand.Seed(time.Now().UnixNano()) 14 | benchx = rand.Intn(1 << 20) 15 | } 16 | 17 | func Test_All(t *testing.T) { 18 | for i := 0; i < 1000000; i++ { 19 | n := rand.Intn(1<<20) + 2 20 | a := Normal(n) 21 | b := Switch(n) 22 | c := IF1(n) 23 | d := IF2(n) 24 | e := Search(n) 25 | f := IF3(n) 26 | if f > 21 { 27 | f = 21 28 | } 29 | if a != b || b != c || c != d || d != e || e != f { 30 | t.Log(n, a, b, c, d, e, f) 31 | t.Fail() 32 | } 33 | } 34 | } 35 | 36 | func Benchmark_Normal(b *testing.B) { 37 | for i := 0; i < b.N; i++ { 38 | Normal(benchx) 39 | } 40 | } 41 | 42 | func Benchmark_Search(b *testing.B) { 43 | for i := 0; i < b.N; i++ { 44 | Search(benchx) 45 | } 46 | } 47 | 48 | func Benchmark_Switch(b *testing.B) { 49 | for i := 0; i < b.N; i++ { 50 | Switch(benchx) 51 | } 52 | } 53 | 54 | func Benchmark_IF1(b *testing.B) { 55 | for i := 0; i < b.N; i++ { 56 | IF1(benchx) 57 | } 58 | } 59 | 60 | func Benchmark_IF2(b *testing.B) { 61 | for i := 0; i < b.N; i++ { 62 | IF2(benchx) 63 | } 64 | } 65 | 66 | func Benchmark_IF3(b *testing.B) { 67 | for i := 0; i < b.N; i++ { 68 | IF3(benchx) 69 | } 70 | } 71 | 72 | func Normal(n int) uint { 73 | var i = uint(0) 74 | for ; n > (1< 1<<1 && n <= 1<<2: 95 | return 2 96 | case n > 1<<2 && n <= 1<<3: 97 | return 3 98 | case n > 1<<3 && n <= 1<<4: 99 | return 4 100 | case n > 1<<4 && n <= 1<<5: 101 | return 5 102 | case n > 1<<5 && n <= 1<<6: 103 | return 6 104 | case n > 1<<6 && n <= 1<<7: 105 | return 7 106 | case n > 1<<7 && n <= 1<<8: 107 | return 8 108 | case n > 1<<8 && n <= 1<<9: 109 | return 9 110 | case n > 1<<9 && n <= 1<<10: 111 | return 10 112 | case n > 1<<10 && n <= 1<<11: 113 | return 11 114 | case n > 1<<11 && n <= 1<<12: 115 | return 12 116 | case n > 1<<12 && n <= 1<<13: 117 | return 13 118 | case n > 1<<13 && n <= 1<<14: 119 | return 14 120 | case n > 1<<14 && n <= 1<<15: 121 | return 15 122 | case n > 1<<15 && n <= 1<<16: 123 | return 16 124 | case n > 1<<16 && n <= 1<<17: 125 | return 17 126 | case n > 1<<17 && n <= 1<<18: 127 | return 18 128 | case n > 1<<18 && n <= 1<<19: 129 | return 19 130 | case n > 1<<19 && n <= 1<<20: 131 | return 20 132 | } 133 | return 21 134 | } 135 | 136 | func IF1(n int) uint { 137 | if n <= 1<<0 { 138 | return 0 139 | } 140 | if n <= 1<<1 { 141 | return 1 142 | } 143 | if n <= 1<<2 { 144 | return 2 145 | } 146 | if n <= 1<<3 { 147 | return 3 148 | } 149 | if n <= 1<<4 { 150 | return 4 151 | } 152 | if n <= 1<<5 { 153 | return 5 154 | } 155 | if n <= 1<<6 { 156 | return 6 157 | } 158 | if n <= 1<<7 { 159 | return 7 160 | } 161 | if n <= 1<<8 { 162 | return 8 163 | } 164 | if n <= 1<<9 { 165 | return 9 166 | } 167 | if n <= 1<<10 { 168 | return 10 169 | } 170 | if n <= 1<<11 { 171 | return 11 172 | } 173 | if n <= 1<<12 { 174 | return 12 175 | } 176 | if n <= 1<<13 { 177 | return 13 178 | } 179 | if n <= 1<<14 { 180 | return 14 181 | } 182 | if n <= 1<<15 { 183 | return 15 184 | } 185 | if n <= 1<<16 { 186 | return 16 187 | } 188 | if n <= 1<<17 { 189 | return 17 190 | } 191 | if n <= 1<<18 { 192 | return 18 193 | } 194 | if n <= 1<<19 { 195 | return 19 196 | } 197 | if n <= 1<<20 { 198 | return 20 199 | } 200 | return 21 201 | } 202 | 203 | func IF2(n int) uint { 204 | if n <= 1<<10 { 205 | if n <= 1<<5 { 206 | if n <= 1<<2 { 207 | if n <= 1<<1 { 208 | return 1 209 | } 210 | return 2 211 | } else { 212 | if n <= 1<<4 { 213 | if n <= 1<<3 { 214 | return 3 215 | } 216 | return 4 217 | } 218 | return 5 219 | } 220 | } else { 221 | if n <= 1<<7 { 222 | if n <= 1<<6 { 223 | return 6 224 | } 225 | return 7 226 | } else { 227 | if n <= 1<<9 { 228 | if n <= 1<<8 { 229 | return 8 230 | } 231 | return 9 232 | } 233 | return 10 234 | } 235 | } 236 | } else { 237 | if n <= 1<<15 { 238 | if n <= 1<<12 { 239 | if n <= 1<<11 { 240 | return 11 241 | } 242 | return 12 243 | } else { 244 | if n <= 1<<14 { 245 | if n <= 1<<13 { 246 | return 13 247 | } 248 | return 14 249 | } 250 | return 15 251 | } 252 | } else { 253 | if n <= 1<<17 { 254 | if n <= 1<<16 { 255 | return 16 256 | } 257 | return 17 258 | } else { 259 | if n <= 1<<19 { 260 | if n <= 1<<18 { 261 | return 18 262 | } 263 | return 19 264 | } 265 | if n <= 1<<20 { 266 | return 20 267 | } 268 | } 269 | } 270 | } 271 | return 21 272 | } 273 | 274 | func IF3(n int) uint { 275 | n-- 276 | c := uint(0) 277 | if (n & 0xffff0000) != 0 { 278 | c += 16 279 | n >>= 16 280 | } 281 | if (n & 0xff00) != 0 { 282 | c += 8 283 | n >>= 8 284 | } 285 | if (n & 0xf0) != 0 { 286 | c += 4 287 | n >>= 4 288 | } 289 | if (n & 0xc) != 0 { 290 | c += 2 291 | n >>= 2 292 | } 293 | if (n & 0x2) != 0 { 294 | c++ 295 | n >>= 1 296 | } 297 | if n != 0 { 298 | c++ 299 | } 300 | return c 301 | } 302 | -------------------------------------------------------------------------------- /labs29/labs29_test.go: -------------------------------------------------------------------------------- 1 | package labs29 2 | 3 | import ( 4 | "bufio" 5 | "code.google.com/p/snappy-go/snappy" 6 | "compress/gzip" 7 | "encoding/json" 8 | "io" 9 | "os" 10 | "testing" 11 | ) 12 | 13 | import "time" 14 | 15 | type M map[string]interface{} 16 | 17 | type Transaction struct { 18 | Time int 19 | API string 20 | Pid int64 21 | Actions []Action 22 | } 23 | 24 | type Action struct { 25 | Type string 26 | Table string 27 | OldData M `json:",omitempty"` 28 | NewData M `json:",omitempty"` 29 | } 30 | 31 | func (t *Transaction) ByteSize() int { 32 | s := 0 33 | for i := 0; i < len(t.Actions); i++ { 34 | s += t.Actions[i].ByteSize() 35 | } 36 | return 8 + 4 + len(t.API) + 8 + 4 + len(t.Actions) + s 37 | } 38 | 39 | func (a *Action) ByteSize() int { 40 | return 4 + len(a.Type) + 4 + len(a.Table) + len(a.OldData)*4 + len(a.OldData)*4 41 | } 42 | 43 | var TestData = Transaction{ 44 | Time: time.Now().Nanosecond(), API: "make_item", Pid: 123, Actions: []Action{ 45 | {Type: "Update", Table: "player_info", 46 | OldData: M{"pid": 123, "coins": 2000}, 47 | NewData: M{"pid": 123, "coins": 1000}, 48 | }, 49 | {Type: "Delete", Table: "player_item", 50 | OldData: M{"id": 2, "pid": 123, "item_id": 100}, 51 | }, 52 | {Type: "Delete", Table: "player_item", 53 | OldData: M{"id": 2, "pid": 123, "item_id": 200}, 54 | }, 55 | {Type: "Insert", Table: "player_item", 56 | NewData: M{"id": 3, "pid": 123, "item_id": 300}, 57 | }, 58 | }, 59 | } 60 | 61 | const TestLines = 10000 62 | 63 | func Test_ByteSize(t *testing.T) { 64 | t.Log(TestData.ByteSize()*TestLines/1000/1000, "MB") 65 | } 66 | 67 | func Test_Normal(t *testing.T) { 68 | var ( 69 | f, _ = os.OpenFile("./json.normal", os.O_WRONLY|os.O_CREATE, 0777) 70 | b = bufio.NewWriter(f) 71 | e = json.NewEncoder(b) 72 | ) 73 | for i := 0; i < TestLines; i++ { 74 | e.Encode(TestData) 75 | } 76 | b.Flush() 77 | f.Close() 78 | } 79 | 80 | func Test_Gzip_Level1(t *testing.T) { 81 | var ( 82 | f, _ = os.OpenFile("./json.gzip1", os.O_WRONLY|os.O_CREATE, 0777) 83 | b = bufio.NewWriter(f) 84 | g, _ = gzip.NewWriterLevel(b, 1) 85 | e = json.NewEncoder(g) 86 | ) 87 | for i := 0; i < TestLines; i++ { 88 | e.Encode(TestData) 89 | } 90 | g.Flush() 91 | g.Close() 92 | b.Flush() 93 | f.Close() 94 | } 95 | 96 | func Test_Gzip_Level5(t *testing.T) { 97 | var ( 98 | f, _ = os.OpenFile("./json.gzip5", os.O_WRONLY|os.O_CREATE, 0777) 99 | b = bufio.NewWriter(f) 100 | g, _ = gzip.NewWriterLevel(b, 5) 101 | e = json.NewEncoder(g) 102 | ) 103 | for i := 0; i < TestLines; i++ { 104 | e.Encode(TestData) 105 | } 106 | g.Flush() 107 | g.Close() 108 | b.Flush() 109 | f.Close() 110 | } 111 | 112 | func Test_Gzip_Level9(t *testing.T) { 113 | var ( 114 | f, _ = os.OpenFile("./json.gzip9", os.O_WRONLY|os.O_CREATE, 0777) 115 | b = bufio.NewWriter(f) 116 | g, _ = gzip.NewWriterLevel(b, 9) 117 | e = json.NewEncoder(g) 118 | ) 119 | for i := 0; i < TestLines; i++ { 120 | e.Encode(TestData) 121 | } 122 | g.Flush() 123 | g.Close() 124 | b.Flush() 125 | f.Close() 126 | } 127 | 128 | func Test_Snappy(t *testing.T) { 129 | var ( 130 | f, _ = os.OpenFile("./json.snappy", os.O_WRONLY|os.O_CREATE, 0777) 131 | g = snappy.NewWriter(f) 132 | b = bufio.NewWriter(g) 133 | e = json.NewEncoder(b) 134 | ) 135 | for i := 0; i < TestLines; i++ { 136 | e.Encode(TestData) 137 | } 138 | b.Flush() 139 | f.Close() 140 | } 141 | 142 | type CountWriter struct { 143 | c int 144 | } 145 | 146 | func (w *CountWriter) Write(p []byte) (n int, err error) { 147 | w.c += len(p) 148 | return len(p), nil 149 | } 150 | 151 | type CountProxyWriter struct { 152 | w io.Writer 153 | c int 154 | } 155 | 156 | func (w *CountProxyWriter) Write(p []byte) (n int, err error) { 157 | w.c += len(p) 158 | return w.w.Write(p) 159 | } 160 | 161 | func Test_Normal_10S(t *testing.T) { 162 | var ( 163 | f = &CountWriter{} 164 | e = json.NewEncoder(f) 165 | s = time.Now() 166 | ) 167 | for { 168 | e.Encode(TestData) 169 | if time.Since(s) >= time.Second*10 { 170 | break 171 | } 172 | } 173 | t.Log(f.c/10/1000/1000, "MB/S") 174 | } 175 | 176 | func Test_Gzip_10S_Level1(t *testing.T) { 177 | var ( 178 | g, _ = gzip.NewWriterLevel(&CountWriter{}, 1) 179 | f = &CountProxyWriter{w: g} 180 | e = json.NewEncoder(f) 181 | s = time.Now() 182 | ) 183 | for { 184 | e.Encode(TestData) 185 | if time.Since(s) >= time.Second*10 { 186 | break 187 | } 188 | } 189 | g.Flush() 190 | g.Close() 191 | t.Log(f.c/10/1000/1000, "MB/S") 192 | } 193 | 194 | func Test_Gzip_10S_Level5(t *testing.T) { 195 | var ( 196 | g, _ = gzip.NewWriterLevel(&CountWriter{}, 5) 197 | f = &CountProxyWriter{w: g} 198 | e = json.NewEncoder(f) 199 | s = time.Now() 200 | ) 201 | for { 202 | e.Encode(TestData) 203 | if time.Since(s) >= time.Second*10 { 204 | break 205 | } 206 | } 207 | g.Flush() 208 | g.Close() 209 | t.Log(f.c/10/1000/1000, "MB/S") 210 | } 211 | 212 | func Test_Gzip_10S_Level9(t *testing.T) { 213 | var ( 214 | g, _ = gzip.NewWriterLevel(&CountWriter{}, 9) 215 | f = &CountProxyWriter{w: g} 216 | e = json.NewEncoder(f) 217 | s = time.Now() 218 | ) 219 | for { 220 | e.Encode(TestData) 221 | if time.Since(s) >= time.Second*10 { 222 | break 223 | } 224 | } 225 | g.Flush() 226 | t.Log(f.c/10/1000/1000, "MB/S") 227 | } 228 | 229 | func Test_Snappy2_10S(t *testing.T) { 230 | var ( 231 | g = snappy.NewWriter(&CountWriter{}) 232 | f = &CountProxyWriter{w: g} 233 | e = json.NewEncoder(f) 234 | s = time.Now() 235 | ) 236 | for { 237 | e.Encode(TestData) 238 | if time.Since(s) >= time.Second*10 { 239 | break 240 | } 241 | } 242 | t.Log(f.c/10/1000/1000, "MB/S") 243 | } 244 | -------------------------------------------------------------------------------- /labs17/labs17_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "regexp" 5 | "strconv" 6 | "testing" 7 | ) 8 | 9 | type convertStep struct { 10 | reg *regexp.Regexp 11 | replace string 12 | } 13 | 14 | var ( 15 | convertSteps []convertStep 16 | sliceUnit []string 17 | sliceUnit2 []rune 18 | upperDigitUnit map[string]string 19 | upperDigitUnit2 map[rune]string 20 | upperDigitUnit3 map[rune]rune 21 | ) 22 | 23 | func init() { 24 | convertSteps = make([]convertStep, 0, 10) 25 | 26 | reg, _ := regexp.Compile(`零角零分$`) 27 | convertSteps = append(convertSteps, convertStep{reg, "整"}) 28 | 29 | reg, _ = regexp.Compile(`零角`) 30 | convertSteps = append(convertSteps, convertStep{reg, "零"}) 31 | 32 | reg, _ = regexp.Compile(`零分$`) 33 | convertSteps = append(convertSteps, convertStep{reg, "整"}) 34 | 35 | reg, _ = regexp.Compile(`零[仟佰拾]`) 36 | convertSteps = append(convertSteps, convertStep{reg, "零"}) 37 | 38 | reg, _ = regexp.Compile(`零{2,}`) 39 | convertSteps = append(convertSteps, convertStep{reg, "零"}) 40 | 41 | reg, _ = regexp.Compile(`零亿`) 42 | convertSteps = append(convertSteps, convertStep{reg, "亿"}) 43 | 44 | reg, _ = regexp.Compile(`零万`) 45 | convertSteps = append(convertSteps, convertStep{reg, "万"}) 46 | 47 | reg, _ = regexp.Compile(`零*元`) 48 | convertSteps = append(convertSteps, convertStep{reg, "元"}) 49 | 50 | reg, _ = regexp.Compile(`亿零{0, 3}万`) 51 | convertSteps = append(convertSteps, convertStep{reg, "^元"}) 52 | 53 | reg, _ = regexp.Compile(`零元`) 54 | convertSteps = append(convertSteps, convertStep{reg, "零"}) 55 | 56 | sliceUnit = []string{"仟", "佰", "拾", "亿", "仟", "佰", "拾", "万", "仟", "佰", "拾", "元", "角", "分"} 57 | sliceUnit2 = []rune{'仟', '佰', '拾', '亿', '仟', '佰', '拾', '万', '仟', '佰', '拾', '元', '角', '分'} 58 | upperDigitUnit = map[string]string{"0": "零", "1": "壹", "2": "贰", "3": "叁", "4": "肆", "5": "伍", "6": "陆", "7": "柒", "8": "捌", "9": "玖"} 59 | upperDigitUnit2 = map[rune]string{'0': "零", '1': "壹", '2': "贰", '3': "叁", '4': "肆", '5': "伍", '6': "陆", '7': "柒", '8': "捌", '9': "玖"} 60 | upperDigitUnit3 = map[rune]rune{'0': '零', '1': '壹', '2': '贰', '3': '叁', '4': '肆', '5': '伍', '6': '陆', '7': '柒', '8': '捌', '9': '玖'} 61 | } 62 | 63 | // 最初的版本 64 | // 65 | func ConvertNumToCny1(num float64) (string, error) { 66 | strnum := strconv.FormatFloat(num*100, 'f', 0, 64) 67 | sliceUnit := []string{"仟", "佰", "拾", "亿", "仟", "佰", "拾", "万", "仟", "佰", "拾", "元", "角", "分"} 68 | s := sliceUnit[len(sliceUnit)-len(strnum) : len(sliceUnit)] 69 | upperDigitUnit := map[string]string{"0": "零", "1": "壹", "2": "贰", "3": "叁", "4": "肆", "5": "伍", "6": "陆", "7": "柒", "8": "捌", "9": "玖"} 70 | str := "" 71 | for k, v := range strnum { 72 | str = str + upperDigitUnit[string(v)] + s[k] 73 | } 74 | 75 | reg, err := regexp.Compile(`零角零分$`) 76 | str = reg.ReplaceAllString(str, "整") 77 | if err != nil { 78 | return "", err 79 | } 80 | 81 | reg, err = regexp.Compile(`零角`) 82 | str = reg.ReplaceAllString(str, "零") 83 | if err != nil { 84 | return "", err 85 | } 86 | 87 | reg, err = regexp.Compile(`零分$`) 88 | str = reg.ReplaceAllString(str, "整") 89 | if err != nil { 90 | return "", err 91 | } 92 | 93 | reg, err = regexp.Compile(`零[仟佰拾]`) 94 | str = reg.ReplaceAllString(str, "零") 95 | if err != nil { 96 | return "", err 97 | } 98 | 99 | reg, err = regexp.Compile(`零{2,}`) 100 | str = reg.ReplaceAllString(str, "零") 101 | if err != nil { 102 | return "", err 103 | } 104 | 105 | reg, err = regexp.Compile(`零亿`) 106 | str = reg.ReplaceAllString(str, "亿") 107 | if err != nil { 108 | return "", err 109 | } 110 | 111 | reg, err = regexp.Compile(`零万`) 112 | str = reg.ReplaceAllString(str, "万") 113 | if err != nil { 114 | return "", err 115 | } 116 | 117 | reg, err = regexp.Compile(`零*元`) 118 | str = reg.ReplaceAllString(str, "元") 119 | if err != nil { 120 | return "", err 121 | } 122 | 123 | reg, err = regexp.Compile(`亿零{0, 3}万`) 124 | str = reg.ReplaceAllString(str, "^元") 125 | if err != nil { 126 | return "", err 127 | } 128 | 129 | reg, err = regexp.Compile(`零元`) 130 | str = reg.ReplaceAllString(str, "零") 131 | if err != nil { 132 | return "", err 133 | } 134 | 135 | return str, nil 136 | } 137 | 138 | // 把正则编译提取到外部,避免反复初始化 139 | // 140 | func ConvertNumToCny2(num float64) (string, error) { 141 | strnum := strconv.FormatFloat(num*100, 'f', 0, 64) 142 | sliceUnit := []string{"仟", "佰", "拾", "亿", "仟", "佰", "拾", "万", "仟", "佰", "拾", "元", "角", "分"} 143 | s := sliceUnit[len(sliceUnit)-len(strnum) : len(sliceUnit)] 144 | upperDigitUnit := map[string]string{"0": "零", "1": "壹", "2": "贰", "3": "叁", "4": "肆", "5": "伍", "6": "陆", "7": "柒", "8": "捌", "9": "玖"} 145 | str := "" 146 | for k, v := range strnum { 147 | str = str + upperDigitUnit[string(v)] + s[k] 148 | } 149 | 150 | for i := 0; i < len(convertSteps); i++ { 151 | str = convertSteps[i].reg.ReplaceAllString(str, convertSteps[i].replace) 152 | } 153 | 154 | return str, nil 155 | } 156 | 157 | // 把变量初始化提取到外部,避免不必要的重复创建 158 | // 159 | func ConvertNumToCny3(num float64) (string, error) { 160 | strnum := strconv.FormatFloat(num*100, 'f', 0, 64) 161 | s := sliceUnit[len(sliceUnit)-len(strnum) : len(sliceUnit)] 162 | str := "" 163 | for k, v := range strnum { 164 | str = str + upperDigitUnit[string(v)] + s[k] 165 | } 166 | 167 | for i := 0; i < len(convertSteps); i++ { 168 | str = convertSteps[i].reg.ReplaceAllString(str, convertSteps[i].replace) 169 | } 170 | 171 | return str, nil 172 | } 173 | 174 | // 把map的key换成rune,避免反复生成字符串 175 | // 176 | func ConvertNumToCny4(num float64) (string, error) { 177 | strnum := strconv.FormatFloat(num*100, 'f', 0, 64) 178 | s := sliceUnit[len(sliceUnit)-len(strnum) : len(sliceUnit)] 179 | str := "" 180 | for k, v := range strnum { 181 | str = str + upperDigitUnit2[v] + s[k] 182 | } 183 | 184 | for i := 0; i < len(convertSteps); i++ { 185 | str = convertSteps[i].reg.ReplaceAllString(str, convertSteps[i].replace) 186 | } 187 | 188 | return str, nil 189 | } 190 | 191 | // 避免字符串反复拼接,并把类型换成rune 192 | // 193 | func ConvertNumToCny5(num float64) (string, error) { 194 | strnum := strconv.FormatFloat(num*100, 'f', 0, 64) 195 | s := sliceUnit2[len(sliceUnit2)-len(strnum) : len(sliceUnit2)] 196 | buff := make([]rune, 0, 2*len(s)) 197 | for k, v := range strnum { 198 | buff = append(buff, upperDigitUnit3[v]) 199 | buff = append(buff, s[k]) 200 | } 201 | str := string(buff) 202 | 203 | for i := 0; i < len(convertSteps); i++ { 204 | str = convertSteps[i].reg.ReplaceAllString(str, convertSteps[i].replace) 205 | } 206 | 207 | return str, nil 208 | } 209 | 210 | func Test_Method1(t *testing.T) { 211 | if str, _ := ConvertNumToCny1(1001.01); str != "壹仟零壹元零壹分" { 212 | t.Fatal() 213 | } 214 | } 215 | 216 | func Test_Method2(t *testing.T) { 217 | if str, _ := ConvertNumToCny2(1001.01); str != "壹仟零壹元零壹分" { 218 | t.Fatal() 219 | } 220 | } 221 | 222 | func Test_Method3(t *testing.T) { 223 | if str, _ := ConvertNumToCny3(1001.01); str != "壹仟零壹元零壹分" { 224 | t.Fatal() 225 | } 226 | } 227 | 228 | func Test_Method4(t *testing.T) { 229 | if str, _ := ConvertNumToCny4(1001.01); str != "壹仟零壹元零壹分" { 230 | t.Fatal() 231 | } 232 | } 233 | 234 | func Test_Method5(t *testing.T) { 235 | if str, _ := ConvertNumToCny5(1001.01); str != "壹仟零壹元零壹分" { 236 | t.Fatal() 237 | } 238 | } 239 | 240 | func Benchmark_Method1(b *testing.B) { 241 | for i := 0; i < b.N; i++ { 242 | ConvertNumToCny1(1001.01) 243 | } 244 | } 245 | 246 | func Benchmark_Method2(b *testing.B) { 247 | for i := 0; i < b.N; i++ { 248 | ConvertNumToCny2(1001.01) 249 | } 250 | } 251 | 252 | func Benchmark_Method3(b *testing.B) { 253 | for i := 0; i < b.N; i++ { 254 | ConvertNumToCny3(1001.01) 255 | } 256 | } 257 | 258 | func Benchmark_Method4(b *testing.B) { 259 | for i := 0; i < b.N; i++ { 260 | ConvertNumToCny4(1001.01) 261 | } 262 | } 263 | 264 | func Benchmark_Method5(b *testing.B) { 265 | for i := 0; i < b.N; i++ { 266 | ConvertNumToCny5(1001.01) 267 | } 268 | } 269 | --------------------------------------------------------------------------------