├── 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 |
--------------------------------------------------------------------------------