├── compiler_reverse_101 ├── token_print │ ├── readme.md │ ├── main.go │ └── print.go ├── ast_print_main_func │ ├── readme.md │ ├── main.go │ └── print.go ├── convert_string_to_byte │ └── hello.go ├── compare_two_expr_with_one │ ├── 1.go │ ├── 2.go │ └── readme.md └── delve_intro │ ├── i_dont_know.go │ ├── random_bug.go │ └── wrong_config.go ├── perf_in_the_wild └── readme.md ├── benchmark_ninja ├── benchstat │ ├── .idea │ │ ├── vcs.xml │ │ ├── .gitignore │ │ ├── modules.xml │ │ └── benchstat.iml │ ├── readme.md │ └── zero_garbage_test.go ├── popular_benchmark_games │ └── readme.md ├── escape_analysis │ └── escape.go ├── string_concat │ └── concat_test.go ├── slice_traverse │ └── horizon_or_vertical_test.go ├── zero_garbage │ └── zero_garbage_test.go └── false_sharing │ └── false_sharing_test.go ├── profiling_master ├── obj_opt │ └── map_with_ptrs_test.go ├── uuidgen │ ├── uuid_gen.go │ └── uuid_gen_real.go ├── cpu_opt │ ├── cpu_opt.go │ └── cpu_opt_ji.go ├── profiling_basics │ └── basic.go ├── mutex_block │ └── mutex_block.go └── double_buffer │ └── double_buffer.go └── language_pitfalls ├── too_many_goroutines └── main.go └── too_many_threads ├── original.go └── fix.go /compiler_reverse_101/token_print/readme.md: -------------------------------------------------------------------------------- 1 | go run print.go 2 | 3 | 会将 main.go 中所有的 token 打印出来 4 | -------------------------------------------------------------------------------- /perf_in_the_wild/readme.md: -------------------------------------------------------------------------------- 1 | # try self aware pprof dump 2 | 3 | https://github.com/mosn/holmes 4 | -------------------------------------------------------------------------------- /compiler_reverse_101/ast_print_main_func/readme.md: -------------------------------------------------------------------------------- 1 | go run print.go 2 | 3 | 会打印所有函数声明的 AST 4 | 5 | -------------------------------------------------------------------------------- /compiler_reverse_101/token_print/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // this is the main function 4 | func main() { 5 | println(1+2) 6 | } 7 | -------------------------------------------------------------------------------- /compiler_reverse_101/ast_print_main_func/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // this is the main function 4 | func main() { 5 | println(1+2) 6 | } 7 | -------------------------------------------------------------------------------- /compiler_reverse_101/convert_string_to_byte/hello.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() { 4 | var a = "hello" 5 | var b = []byte(a) 6 | println(b) 7 | } 8 | -------------------------------------------------------------------------------- /compiler_reverse_101/compare_two_expr_with_one/1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type person struct { 4 | age int 5 | } 6 | 7 | func main() { 8 | var a = &person{111} 9 | println(a) 10 | } 11 | -------------------------------------------------------------------------------- /compiler_reverse_101/compare_two_expr_with_one/2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type person struct { 4 | age int 5 | } 6 | 7 | func main() { 8 | var b = person{111} 9 | var a = &b 10 | println(a) 11 | } 12 | 13 | -------------------------------------------------------------------------------- /benchmark_ninja/benchstat/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /benchmark_ninja/benchstat/.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Datasource local storage ignored files 5 | /dataSources/ 6 | /dataSources.local.xml 7 | # Editor-based HTTP Client requests 8 | /httpRequests/ 9 | -------------------------------------------------------------------------------- /benchmark_ninja/popular_benchmark_games/readme.md: -------------------------------------------------------------------------------- 1 | https://benchmarksgame-team.pages.debian.net/benchmarksgame/index.html 2 | 3 | https://www.techempower.com/benchmarks/ 4 | 5 | https://github.com/smallnest/go-web-framework-benchmark 6 | 7 | https://github.com/julienschmidt/go-http-routing-benchmark 8 | -------------------------------------------------------------------------------- /compiler_reverse_101/delve_intro/i_dont_know.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() { 4 | for i:= 0;i< 1000;i++ { 5 | if i % 2 == 0 { 6 | iDontKnow(i) 7 | } 8 | } 9 | 10 | } 11 | 12 | // 我不知道这个函数什么时候会被调用到 13 | func iDontKnow(i int) { 14 | println("现在我知道了") 15 | println("你能把调用栈打印出来吗") 16 | } 17 | 18 | -------------------------------------------------------------------------------- /benchmark_ninja/benchstat/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /benchmark_ninja/benchstat/.idea/benchstat.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /compiler_reverse_101/delve_intro/random_bug.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // 这个函数只在 i == 1000 的时候会触发 bug, 4 | // 现在的环境没法改代码,怎么通过 delve 来触发这个 bug? 5 | func someBugFunction(i int) { 6 | if i == 1000 { 7 | panic("here bug go go") 8 | } 9 | } 10 | 11 | func main() { 12 | for i := 0; i < 10; i++ { 13 | someBugFunction(i) 14 | } 15 | } 16 | 17 | -------------------------------------------------------------------------------- /benchmark_ninja/benchstat/readme.md: -------------------------------------------------------------------------------- 1 | 翻墙困难的话, 2 | 3 | git clone https://github.com/golang/perf.git 4 | 5 | 进 benchstat 的目录,go install 6 | 7 | go test -run=NONE -bench=Garbage -benchmem -count=5 > old.txt 8 | 9 | change code 10 | 11 | go test -run=NONE -bench=Garbage -benchmem -count=5 > new.txt 12 | 13 | then benchstat old.txt new.txt 14 | 15 | -------------------------------------------------------------------------------- /compiler_reverse_101/ast_print_main_func/print.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "go/ast" 5 | "go/parser" 6 | "go/token" 7 | ) 8 | 9 | func main() { 10 | fset := token.NewFileSet() 11 | // if the src parameter is nil, then will auto read the second filepath file 12 | f, _ := parser.ParseFile(fset, "./main.go", nil, parser.Mode(0)) 13 | 14 | for _, d := range f.Decls { 15 | ast.Print(fset, d) 16 | } 17 | } 18 | 19 | -------------------------------------------------------------------------------- /benchmark_ninja/escape_analysis/escape.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func returnLocalPointer() *int { 6 | var a = 1 7 | return &a 8 | } 9 | 10 | func localTooLarge() { 11 | var tl = make([]int, 10000) 12 | _ = tl 13 | } 14 | 15 | func nonConstantSlice(l int) { 16 | var ncs = make([]int, l) 17 | _ = ncs 18 | } 19 | 20 | func fmtSeriesFunc() { 21 | var i = fmt.Sprint(10) 22 | _ = i 23 | } 24 | 25 | func main() {} 26 | -------------------------------------------------------------------------------- /profiling_master/obj_opt/map_with_ptrs_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "testing" 4 | 5 | func BenchmarkMapWithoutPtrs(b *testing.B) { 6 | for i:=0;i< b.N;i++{ 7 | var m = make(map[int]int) 8 | for i:=0;i<10;i++ { 9 | m[i] = i 10 | } 11 | } 12 | } 13 | 14 | func BenchmarkMapWithPtrs(b *testing.B) { 15 | for i:=0;i< b.N;i++{ 16 | var m = make(map[int]*int) 17 | for i:=0;i<10;i++ { 18 | var v = i 19 | m[i] = &v 20 | } 21 | } 22 | } 23 | 24 | -------------------------------------------------------------------------------- /language_pitfalls/too_many_goroutines/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "net/http" 6 | _ "net/http/pprof" 7 | "time" 8 | ) 9 | 10 | func sayhello(wr http.ResponseWriter, r *http.Request) {} 11 | 12 | func main() { 13 | for i := 0; i < 1000000; i++ { 14 | go func() { 15 | time.Sleep(time.Second * 10) 16 | }() 17 | } 18 | http.HandleFunc("/", sayhello) 19 | err := http.ListenAndServe(":10003", nil) 20 | if err != nil { 21 | log.Fatal("ListenAndServe:", err) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /compiler_reverse_101/delve_intro/wrong_config.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() { 4 | initConfig() 5 | } 6 | 7 | // 我用的 mq 的 sdk 线下好像读的配置选项不太对,我想看看他到底读了啥 8 | type Config struct { 9 | Address string 10 | } 11 | 12 | var correctConfig = Config { 13 | Address : "10.100.1.131", 14 | } 15 | 16 | var wrongConfig = Config { 17 | Address : "127.0.0.1", 18 | } 19 | 20 | func initConfig() { 21 | // a lot of read code 22 | var conf = wrongConfig 23 | useConf(conf) 24 | } 25 | 26 | func useConf(c Config) {} 27 | -------------------------------------------------------------------------------- /benchmark_ninja/string_concat/concat_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func BenchmarkPlusConcat(b *testing.B) { 9 | var main string 10 | for i := 0; i < b.N; i++ { 11 | main = "" 12 | main += "userid : " + "1" 13 | main += "localtion : " + "ab" 14 | } 15 | } 16 | 17 | func BenchmarkSprintf(b *testing.B) { 18 | var main string 19 | for i := 0; i < b.N; i++ { 20 | main = "" 21 | main += fmt.Sprintf("userid : %v", "1") 22 | main += fmt.Sprintf("location : %v", "ab") 23 | } 24 | } 25 | 26 | -------------------------------------------------------------------------------- /profiling_master/uuidgen/uuid_gen.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "io" 5 | "log" 6 | _ "net/http/pprof" 7 | "os/exec" 8 | 9 | "net/http" 10 | ) 11 | 12 | func sayhello(wr http.ResponseWriter, r *http.Request) { 13 | uuid, _ := exec.Command("uuidgen").Output() 14 | 15 | wr.Header()["Content-Type"] = []string{"application/text"} 16 | io.WriteString(wr, string(uuid)) 17 | } 18 | 19 | func main() { 20 | http.HandleFunc("/", sayhello) 21 | err := http.ListenAndServe(":10003", nil) 22 | if err != nil { 23 | log.Fatal("ListenAndServe:", err) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /profiling_master/uuidgen/uuid_gen_real.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "io" 5 | "log" 6 | _ "net/http/pprof" 7 | 8 | //"os/exec" 9 | 10 | "net/http" 11 | 12 | uuid "github.com/satori/go.uuid" 13 | ) 14 | 15 | func sayhello(wr http.ResponseWriter, r *http.Request) { 16 | uu, _ := uuid.NewV4() 17 | 18 | wr.Header()["Content-Type"] = []string{"application/text"} 19 | io.WriteString(wr, uu.String()) 20 | } 21 | 22 | func main() { 23 | http.HandleFunc("/", sayhello) 24 | err := http.ListenAndServe(":10003", nil) 25 | if err != nil { 26 | log.Fatal("ListenAndServe:", err) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /benchmark_ninja/slice_traverse/horizon_or_vertical_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "testing" 4 | 5 | var arr = make([][]int, 10000) 6 | 7 | func init() { 8 | for i := 0; i < 10000; i++ { 9 | arr[i] = make([]int, 10000) 10 | } 11 | } 12 | 13 | func BenchmarkHorizontal(b *testing.B) { 14 | for i := 0; i < b.N; i++ { 15 | for x := 0; x < len(arr); x++ { 16 | for y := 0; y < len(arr); y++ { 17 | arr[x][y] = 1 18 | } 19 | } 20 | } 21 | } 22 | 23 | func BenchmarkVertical(b *testing.B) { 24 | for i := 0; i < b.N; i++ { 25 | for x := 0; x < len(arr); x++ { 26 | for y := 0; y < len(arr); y++ { 27 | arr[y][x] = 1 28 | } 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /profiling_master/cpu_opt/cpu_opt.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "io" 5 | "log" 6 | _ "net/http/pprof" 7 | 8 | "net/http" 9 | "encoding/json" 10 | ) 11 | 12 | var bigMap = make(map[int]int) 13 | func init() { 14 | for i:=0;i<10000;i++ { 15 | bigMap[i] = i + 1 16 | } 17 | } 18 | 19 | 20 | func sayhello(wr http.ResponseWriter, r *http.Request) { 21 | d, _ := json.Marshal(bigMap) 22 | wr.Header()["Content-Type"] = []string{"application/json"} 23 | io.WriteString(wr, string(d)) 24 | 25 | } 26 | 27 | func main() { 28 | http.HandleFunc("/", sayhello) 29 | err := http.ListenAndServe(":10003", nil) 30 | if err != nil { 31 | log.Fatal("ListenAndServe:", err) 32 | } 33 | } 34 | 35 | -------------------------------------------------------------------------------- /profiling_master/profiling_basics/basic.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "io" 5 | "log" 6 | _ "net/http/pprof" // 一般开 pprof,在你的 main.go 里加上这一行就行了 7 | 8 | "net/http" 9 | ) 10 | 11 | func sayhello(wr http.ResponseWriter, r *http.Request) { 12 | wr.Header()["Content-Type"] = []string{"application/json"} 13 | io.WriteString(wr, "hello") 14 | 15 | } 16 | 17 | func main() { 18 | http.HandleFunc("/", sayhello) 19 | err := http.ListenAndServe(":10003", nil) 20 | if err != nil { 21 | log.Fatal("ListenAndServe:", err) 22 | } 23 | } 24 | 25 | // 也可以像 etcd 那样做一些定制 26 | // https://github.com/etcd-io/etcd/blob/e2d67f2e3bfa6f72178e26557bb22cc1482c418c/pkg/debugutil/pprof.go#L26 27 | // 有些公司内有热开启/关闭 pprof 的需求 28 | -------------------------------------------------------------------------------- /profiling_master/cpu_opt/cpu_opt_ji.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "io" 5 | "log" 6 | _ "net/http/pprof" 7 | 8 | "net/http" 9 | json "github.com/json-iterator/go" 10 | 11 | ) 12 | 13 | var bigMap = make(map[int]int) 14 | func init() { 15 | for i:=0;i<10000;i++ { 16 | bigMap[i] = i + 1 17 | } 18 | } 19 | 20 | 21 | func sayhello(wr http.ResponseWriter, r *http.Request) { 22 | d, _ := json.Marshal(bigMap) 23 | wr.Header()["Content-Type"] = []string{"application/json"} 24 | io.WriteString(wr, string(d)) 25 | 26 | } 27 | 28 | func main() { 29 | http.HandleFunc("/", sayhello) 30 | err := http.ListenAndServe(":10003", nil) 31 | if err != nil { 32 | log.Fatal("ListenAndServe:", err) 33 | } 34 | } 35 | 36 | -------------------------------------------------------------------------------- /language_pitfalls/too_many_threads/original.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | /* 4 | #include 5 | #include 6 | #include 7 | void output(char *str) { 8 | usleep(1000000); 9 | printf("%s\n", str); 10 | } 11 | */ 12 | import "C" 13 | import "unsafe" 14 | 15 | import "net/http" 16 | import _ "net/http/pprof" 17 | 18 | func init() { 19 | go http.ListenAndServe(":10003", nil) 20 | } 21 | 22 | func main() { 23 | for i := 0;i < 1000;i++ { 24 | go func(){ 25 | str := "hello cgo" 26 | //change to char* 27 | cstr := C.CString(str) 28 | C.output(cstr) 29 | C.free(unsafe.Pointer(cstr)) 30 | 31 | }() 32 | } 33 | select{} 34 | } 35 | -------------------------------------------------------------------------------- /profiling_master/mutex_block/mutex_block.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "io" 5 | "log" 6 | "time" 7 | "sync" 8 | _ "net/http/pprof" 9 | 10 | "net/http" 11 | ) 12 | 13 | var mu sync.Mutex 14 | var data = map[string]string{ 15 | "hint" : "hello world", 16 | } 17 | 18 | func sayhello(wr http.ResponseWriter, r *http.Request) { 19 | mu.Lock() 20 | defer mu.Unlock() 21 | buf := data["hint"] 22 | 23 | // 假设这里是一些非常慢的 io 操作 24 | time.Sleep(time.Millisecond * 10) 25 | 26 | wr.Header()["Content-Type"] = []string{"application/json"} 27 | io.WriteString(wr, buf) 28 | } 29 | 30 | func main() { 31 | http.HandleFunc("/", sayhello) 32 | err := http.ListenAndServe(":10003", nil) 33 | if err != nil { 34 | log.Fatal("ListenAndServe:", err) 35 | } 36 | } 37 | 38 | -------------------------------------------------------------------------------- /compiler_reverse_101/token_print/print.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "go/scanner" 6 | "go/token" 7 | "io/ioutil" 8 | ) 9 | 10 | func main() { 11 | // src is the input that we want to tokenize. 12 | src, _ := ioutil.ReadFile(`main.go`) 13 | 14 | // Initialize the scanner. 15 | var s scanner.Scanner 16 | fset := token.NewFileSet() // positions are relative to fset 17 | file := fset.AddFile("", fset.Base(), len(src)) // register input "file" 18 | s.Init(file, src, nil /* no error handler */, scanner.ScanComments) 19 | 20 | // Repeated calls to Scan yield the token sequence found in the input. 21 | fmt.Printf("%s\t%s\t%s\n", "pos", "token", "literal") 22 | for { 23 | pos, tok, lit := s.Scan() 24 | if tok == token.EOF { 25 | break 26 | } 27 | fmt.Printf("%s\t%s\t%q\n", fset.Position(pos), tok, lit) 28 | } 29 | } 30 | 31 | -------------------------------------------------------------------------------- /benchmark_ninja/benchstat/zero_garbage_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "sync" 5 | "testing" 6 | ) 7 | 8 | var reqSlicePool = sync.Pool{ 9 | New: func() interface{} { 10 | var sl = make([]byte, 0) 11 | return &sl 12 | }, 13 | } 14 | 15 | type reqStruct struct { 16 | userData []byte 17 | } 18 | 19 | func handleRequestWithPool(sliceLen int) { 20 | var userData = reqSlicePool.Get().(*[]byte) 21 | defer reqSlicePool.Put(userData) 22 | 23 | if len(*userData) < sliceLen { 24 | *userData = make([]byte, sliceLen) 25 | } 26 | 27 | // 往 userData 里塞一些数据,这里就省略了 28 | 29 | var req = reqStruct{userData: *userData} 30 | _ = req 31 | } 32 | 33 | func handleRequestWithoutPool(sliceLen int) { 34 | var userData = make([]byte, sliceLen) 35 | // 往 userData 里塞一些数据,这里就省略了 36 | 37 | var req = reqStruct{userData: userData} 38 | _ = req 39 | } 40 | 41 | func BenchmarkZeroGarbage(b *testing.B) { 42 | for i := 0; i < b.N; i++ { 43 | handleRequestWithPool(10) 44 | //handleRequestWithoutPool(10) 45 | } 46 | } 47 | 48 | -------------------------------------------------------------------------------- /benchmark_ninja/zero_garbage/zero_garbage_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "sync" 5 | "testing" 6 | ) 7 | 8 | var reqSlicePool = sync.Pool{ 9 | New: func() interface{} { 10 | var sl = make([]byte, 0) 11 | return &sl 12 | }, 13 | } 14 | 15 | type reqStruct struct { 16 | userData []byte 17 | } 18 | 19 | func handleRequestWithPool(sliceLen int) { 20 | var userData = reqSlicePool.Get().(*[]byte) 21 | defer reqSlicePool.Put(userData) 22 | 23 | if len(*userData) < sliceLen { 24 | *userData = make([]byte, sliceLen) 25 | } 26 | 27 | // 往 userData 里塞一些数据,这里就省略了 28 | 29 | var req = reqStruct{userData: *userData} 30 | _ = req 31 | } 32 | 33 | func handleRequestWithoutPool(sliceLen int) { 34 | var userData = make([]byte, sliceLen) 35 | // 往 userData 里塞一些数据,这里就省略了 36 | 37 | var req = reqStruct{userData: userData} 38 | _ = req 39 | } 40 | 41 | func BenchmarkZeroGarbage(b *testing.B) { 42 | for i := 0; i < b.N; i++ { 43 | handleRequestWithPool(10) 44 | } 45 | } 46 | 47 | func BenchmarkHasGarbage(b *testing.B) { 48 | for i := 0; i < b.N; i++ { 49 | handleRequestWithoutPool(10) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /compiler_reverse_101/compare_two_expr_with_one/readme.md: -------------------------------------------------------------------------------- 1 | ## 操作步骤 2 | 3 | ``` 4 | ❯❯❯ cat -n 1.go 5 | 1 package main 6 | 2 7 | 3 type person struct { 8 | 4 age int 9 | 5 } 10 | 6 11 | 7 func main() { 12 | 8 var a = &person{111} 13 | 9 println(a) 14 | 10 } 15 | ``` 16 | 17 | 我们要看第 8 行编译后变成啥了: 18 | 19 | ``` 20 | ❯❯❯ go tool compile -S 1.go | grep "1.go:8" 21 | 0x001d 00029 (1.go:8) PCDATA $0, $0 22 | 0x001d 00029 (1.go:8) PCDATA $1, $0 23 | 0x001d 00029 (1.go:8) MOVQ $0, ""..autotmp_2+8(SP) 24 | 0x0026 00038 (1.go:8) MOVQ $111, ""..autotmp_2+8(SP) 25 | ``` 26 | 27 | 两行的版本: 28 | 29 | ``` 30 | ❯❯❯ cat -n 2.go 31 | 1 package main 32 | 2 33 | 3 type person struct { 34 | 4 age int 35 | 5 } 36 | 6 37 | 7 func main() { 38 | 8 var b = person{111} 39 | 9 var a = &b 40 | 10 println(a) 41 | 11 } 42 | 12 43 | ``` 44 | 45 | 我们要看第 8 和第 9 行: 46 | 47 | ``` 48 | ❯❯❯ go tool compile -S 2.go | grep -E '(2.go:8|2.go:9)' 49 | 0x001d 00029 (2.go:8) PCDATA $0, $0 50 | 0x001d 00029 (2.go:8) PCDATA $1, $0 51 | 0x001d 00029 (2.go:8) MOVQ $0, "".b+8(SP) 52 | 0x0026 00038 (2.go:8) MOVQ $111, "".b+8(SP) 53 | ``` 54 | 55 | 可以看到,这里的一行版本的代码和两行版本的代码最终编译出的结果是完全一致的,没有任何区别。 56 | 57 | -------------------------------------------------------------------------------- /language_pitfalls/too_many_threads/fix.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | /* 4 | #include 5 | #include 6 | #include 7 | void output(char *str) { 8 | usleep(1000000); 9 | printf("%s\n", str); 10 | } 11 | */ 12 | import "C" 13 | 14 | import ( 15 | "net/http" 16 | "unsafe" 17 | 18 | "log" 19 | _ "net/http/pprof" 20 | "runtime" 21 | "sync" 22 | ) 23 | 24 | func init() { 25 | go http.ListenAndServe(":10003", nil) 26 | } 27 | 28 | func main() { 29 | for i := 0; i < 1000; i++ { 30 | go func() { 31 | str := "hello cgo" 32 | //change to char* 33 | cstr := C.CString(str) 34 | C.output(cstr) 35 | C.free(unsafe.Pointer(cstr)) 36 | 37 | }() 38 | } 39 | killThreadService() 40 | select {} 41 | } 42 | 43 | func sayhello(wr http.ResponseWriter, r *http.Request) { 44 | KillOne() 45 | } 46 | 47 | func killThreadService() { 48 | http.HandleFunc("/", sayhello) 49 | err := http.ListenAndServe(":10003", nil) 50 | if err != nil { 51 | log.Fatal("ListenAndServe:", err) 52 | } 53 | } 54 | 55 | // KillOne kills a thread 56 | func KillOne() { 57 | var wg sync.WaitGroup 58 | wg.Add(1) 59 | 60 | go func() { 61 | defer wg.Done() 62 | runtime.LockOSThread() 63 | return 64 | }() 65 | 66 | wg.Wait() 67 | } 68 | 69 | 70 | -------------------------------------------------------------------------------- /benchmark_ninja/false_sharing/false_sharing_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "sync" 5 | "sync/atomic" 6 | "testing" 7 | ) 8 | 9 | type nopad struct { 10 | x uint64 11 | y uint64 12 | } 13 | 14 | type withpad struct { 15 | x uint64 16 | _pad [7]uint64 17 | y uint64 18 | } 19 | 20 | func BenchmarkNoPad(b *testing.B) { 21 | for i := 0; i < b.N; i++ { 22 | var np nopad 23 | var wg sync.WaitGroup 24 | wg.Add(20) 25 | for i := 0; i < 10; i++ { 26 | go func() { 27 | defer wg.Done() 28 | for { 29 | if atomic.AddUint64(&np.x, 1) >= 10000000 { 30 | return 31 | } 32 | } 33 | }() 34 | } 35 | for i := 0; i < 10; i++ { 36 | go func() { 37 | defer wg.Done() 38 | for { 39 | if atomic.AddUint64(&np.y, 1) >= 10000000 { 40 | return 41 | } 42 | } 43 | }() 44 | } 45 | wg.Wait() 46 | } 47 | } 48 | 49 | func BenchmarkWithPad(b *testing.B) { 50 | for i := 0; i < b.N; i++ { 51 | var np withpad 52 | var wg sync.WaitGroup 53 | wg.Add(20) 54 | for i := 0; i < 10; i++ { 55 | go func() { 56 | defer wg.Done() 57 | for { 58 | if atomic.AddUint64(&np.x, 1) >= 10000000 { 59 | return 60 | } 61 | } 62 | }() 63 | } 64 | for i := 0; i < 10; i++ { 65 | go func() { 66 | defer wg.Done() 67 | for { 68 | if atomic.AddUint64(&np.y, 1) >= 10000000 { 69 | return 70 | } 71 | } 72 | }() 73 | } 74 | wg.Wait() 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /profiling_master/double_buffer/double_buffer.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "sync" 5 | "sync/atomic" 6 | ) 7 | 8 | var config atomic.Value 9 | 10 | func init() { 11 | var initialConfig = &MyConfig{ 12 | WhiteList: make(map[int]struct{}), 13 | } 14 | config.Store(initialConfig) 15 | } 16 | 17 | type MyConfig struct { 18 | WhiteList map[int]struct{} 19 | } 20 | 21 | func getConfig() *MyConfig { 22 | return config.Load().(*MyConfig) 23 | } 24 | 25 | func updateConfig1() { 26 | var newConfig = &MyConfig{ 27 | WhiteList: make(map[int]struct{}), 28 | } 29 | 30 | // do a lot of computation 31 | for i := 0; i < 10000; i++ { 32 | newConfig.WhiteList[i] = struct{}{} 33 | } 34 | 35 | config.Store(newConfig) 36 | } 37 | 38 | // partial update 39 | func updateConfig2() { 40 | var oldConfig = getConfig() 41 | var newConfig = &MyConfig{ 42 | WhiteList: make(map[int]struct{}), 43 | } 44 | 45 | // copy from old 46 | for k, v := range oldConfig.WhiteList { 47 | newConfig.WhiteList[k] = v 48 | } 49 | 50 | // add some new keys 51 | newConfig.WhiteList[121212] = struct{}{} 52 | newConfig.WhiteList[23333] = struct{}{} 53 | 54 | config.Store(newConfig) 55 | } 56 | 57 | var updateLock sync.Mutex 58 | 59 | // 如果 update 本身可能出现并发 60 | func updateConfig3() { 61 | // lock update 62 | updateLock.Lock() 63 | defer updateLock.Unlock() 64 | 65 | var oldConfig = getConfig() 66 | var newConfig = &MyConfig{ 67 | WhiteList: make(map[int]struct{}), 68 | } 69 | 70 | // copy from old 71 | for k, v := range oldConfig.WhiteList { 72 | newConfig.WhiteList[k] = v 73 | } 74 | 75 | // add some new keys 76 | newConfig.WhiteList[121212] = struct{}{} 77 | newConfig.WhiteList[23333] = struct{}{} 78 | 79 | config.Store(newConfig) 80 | 81 | } 82 | 83 | func main() {} 84 | --------------------------------------------------------------------------------