/
main.go
75 lines (61 loc) · 1.42 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
package main
import (
"fmt"
"runtime"
"time"
)
// *** Caveat 1: Spawning goroutines in a loop
func spawnInALoop() {
for i := 0; i < 10; i++ {
// Our goroutine is a closure, and closures can
// access variables in the outer scope, so we can
// grab i here to give each goroutine an ID, right?
// (Hint: wrong.)
go func() {
fmt.Println("Goroutine", i)
}() // <- Don't forget to call () the closure
}
time.Sleep(100 * time.Millisecond)
}
func spawnInALoopFixed() {
for i := 0; i < 10; i++ {
// Always pass any start value properly as a
// function parameter. This way, nothing can go wrong.
go func(n int) {
fmt.Println("Goroutine", n)
}(i) // We pass i here as an argument
}
time.Sleep(100 * time.Millisecond)
}
// *** Caveat 2: Goroutine leak
type Worker struct {
Ch chan string
}
func (w *Worker) work() {
for {
w.Ch <- "worker here!"
}
}
func NewWorker() *Worker {
w := &Worker{Ch: make(chan string, 100)}
go w.work()
return w
}
func goroutineleak() {
w := NewWorker()
fmt.Println(<-w.Ch)
// After this point, w goes out of scope
// but the goroutine continues to exist
// (and so does w). Goroutine leak!
}
func main() {
fmt.Println("*** Spawn in a loop ***")
spawnInALoop()
fmt.Println("\n*** Fixed ***")
spawnInALoopFixed()
fmt.Println("\n*** Goroutine leak ***")
fmt.Println(runtime.NumGoroutine())
goroutineleak()
fmt.Println(runtime.NumGoroutine())
fmt.Println("\n*** ***")
}