File tree Expand file tree Collapse file tree 8 files changed +244
-1
lines changed
examples/basic/goroutines Expand file tree Collapse file tree 8 files changed +244
-1
lines changed Original file line number Diff line number Diff line change @@ -53,6 +53,11 @@ clean:
5353install :
5454 $(GOINSTALL ) $(BIN_DIR )
5555
56+ .PHONY : vet
57+ vet :
58+ go vet ./...
59+ staticcheck ./...
60+
5661.PHONY : run
5762run :
5863 $(GORUN ) $(CMD_PKG ) -onetime -example ${EXAMPLE}
Original file line number Diff line number Diff line change 11package goroutines
22
3- import "github.com/devlights/try-golang/mapping"
3+ import (
4+ "github.com/devlights/try-golang/examples/basic/goroutines/leak"
5+ "github.com/devlights/try-golang/mapping"
6+ )
47
58type (
69 register struct {}
@@ -23,4 +26,6 @@ func (r *register) Regist(m mapping.ExampleMapping) {
2326 m ["goroutines_using_chan_semaphore" ] = UsingChanSemaphore
2427 m ["goroutines_using_mutex" ] = UsingMutex
2528 m ["goroutines_with_context_deadline" ] = WithContextDeadline
29+
30+ leak .NewRegister ().Regist (m )
2631}
Original file line number Diff line number Diff line change 1+ package leak
2+
3+ import (
4+ "context"
5+ "time"
6+
7+ "github.com/devlights/gomy/output"
8+ )
9+
10+ // AbandonedReceiver -- goroutineリークが発生するパターンのサンプルです。
11+ //
12+ // チャネルの送受信の実装があるが、タイミングによっては送信側がいなくなってしまうパターン。
13+ // 受信側のgoroutineが永遠に待ち続けるので終了しません。
14+ //
15+ // 解決方法としては、送信側が適切に使い終わったチャネルを閉じること。
16+ //
17+ // REFERENCES:
18+ // - https://betterprogramming.pub/common-goroutine-leaks-that-you-should-avoid-fe12d12d6ee
19+ func AbandonedReceiver () error {
20+ var (
21+ ctx , cxl = context .WithTimeout (context .Background (), 10 * time .Millisecond )
22+ ch = make (chan int )
23+ iowait = func () {
24+ time .Sleep (1 * time .Second )
25+ }
26+ fn = func (ch <- chan int ) {
27+ iowait ()
28+ data := <- ch
29+ output .Stdoutl ("[recv]" , data )
30+ }
31+ )
32+ defer cxl ()
33+
34+ go fn (ch )
35+
36+ select {
37+ case ch <- 1 :
38+ output .Stdoutl ("[send]" , 1 )
39+ case <- ctx .Done ():
40+ }
41+
42+ //
43+ // チャネルにデータを送信するものがいなくなるので
44+ // 上のgoroutineはプロセスが起動中は永遠に終了しません。
45+ //
46+ time .Sleep (1 * time .Second )
47+
48+ return nil
49+ }
Original file line number Diff line number Diff line change 1+ package leak
2+
3+ import (
4+ "context"
5+ "time"
6+
7+ "github.com/devlights/gomy/output"
8+ )
9+
10+ // AbandonedSender -- goroutineリークが発生するパターンのサンプルです。
11+ //
12+ // チャネルの送受信の実装があるが、タイミングによっては受信側がいなくなってしまうパターン。
13+ // 送信側のgoroutineが永遠に待ち続けるので終了しません。
14+ //
15+ // 解決方法としては、Bufferedなチャネルを使うこと。
16+ //
17+ // REFERENCES:
18+ // - https://betterprogramming.pub/common-goroutine-leaks-that-you-should-avoid-fe12d12d6ee
19+ func AbandonedSender () error {
20+ var (
21+ ctx , cxl = context .WithTimeout (context .Background (), 10 * time .Millisecond )
22+ ch = make (chan int )
23+ iowait = func () {
24+ time .Sleep (1 * time .Second )
25+ }
26+ fn = func (ch chan <- int ) {
27+ iowait ()
28+ ch <- 1
29+ output .Stdoutl ("[send]" , 1 )
30+ }
31+ )
32+ defer cxl ()
33+
34+ go fn (ch )
35+ select {
36+ case v := <- ch :
37+ output .Stdoutl ("[recv]" , v )
38+ case <- ctx .Done ():
39+ }
40+
41+ //
42+ // チャネルからデータを受信するものがいなくなるので
43+ // 上のgoroutineはプロセスが起動中は永遠に終了しません。
44+ //
45+ time .Sleep (1 * time .Second )
46+
47+ return nil
48+ }
Original file line number Diff line number Diff line change 1+ package leak
2+
3+ import "github.com/devlights/try-golang/mapping"
4+
5+ type (
6+ register struct {}
7+ )
8+
9+ // NewRegister -- このパッケージ用のサンプルを登録する mapping.Register を生成します。
10+ func NewRegister () mapping.Register {
11+ return new (register )
12+ }
13+
14+ // Regist -- 登録します.
15+ func (r * register ) Regist (m mapping.ExampleMapping ) {
16+ m ["goroutines_leak_forgotten_sender" ] = ForgottenSender
17+ m ["goroutines_leak_forgotten_receiver" ] = ForgottenReceiver
18+ m ["goroutines_leak_abandoned_sender" ] = AbandonedSender
19+ m ["goroutines_leak_abandoned_receiver" ] = AbandonedReceiver
20+ m ["goroutines_leak_sender_after_error_check" ] = SenderAfterErrorCheck
21+ }
Original file line number Diff line number Diff line change 1+ package leak
2+
3+ import (
4+ "time"
5+
6+ "github.com/devlights/gomy/output"
7+ )
8+
9+ // ForgottenReceiver -- goroutineリークが発生するパターンのサンプルです。
10+ //
11+ // チャネルを作成し、チャネルの受信側がいないパターン。
12+ // 送信側のgoroutineが永遠に待ち続けるので終了しません。
13+ //
14+ // 解決方法としては、Bufferedなチャネルを使うこと。
15+ //
16+ // REFERENCES:
17+ // - https://betterprogramming.pub/common-goroutine-leaks-that-you-should-avoid-fe12d12d6ee
18+ func ForgottenReceiver () error {
19+ var (
20+ fn = func (ch chan <- int ) {
21+ ch <- 1
22+ output .Stdoutl ("[goroutine leak]" , 1 )
23+ }
24+ ch = make (chan int )
25+ )
26+
27+ go fn (ch )
28+
29+ //
30+ // チャネルのデータを受信するものがいないので
31+ // 上のgoroutineはプロセスが起動中は永遠に終了しません。
32+ //
33+ time .Sleep (1 * time .Second )
34+
35+ return nil
36+ }
Original file line number Diff line number Diff line change 1+ package leak
2+
3+ import (
4+ "time"
5+
6+ "github.com/devlights/gomy/output"
7+ )
8+
9+ // ForgottenSender -- goroutineリークが発生するパターンのサンプルです。
10+ //
11+ // チャネルを作成し、チャネルの送信側がいないパターン。
12+ // 受信側のgoroutineが永遠に待ち続けるので終了しません。
13+ //
14+ // 解決方法としては、送信側が適切に使い終わったチャネルを閉じること。
15+ //
16+ // REFERENCES:
17+ // - https://betterprogramming.pub/common-goroutine-leaks-that-you-should-avoid-fe12d12d6ee
18+ func ForgottenSender () error {
19+ var (
20+ fn = func (ch <- chan int ) {
21+ data := <- ch
22+ output .Stdoutl ("[goroutine leak]" , data )
23+ }
24+ ch = make (chan int )
25+ )
26+
27+ go fn (ch )
28+
29+ //
30+ // チャネルにデータを送信するものがいないので
31+ // 上のgoroutineはプロセスが起動中は永遠に終了しません。
32+ //
33+ time .Sleep (1 * time .Second )
34+
35+ return nil
36+ }
Original file line number Diff line number Diff line change 1+ package leak
2+
3+ import (
4+ "errors"
5+
6+ "github.com/devlights/gomy/output"
7+ )
8+
9+ // SenderAfterErrorCheck -- goroutineリークが発生するパターンのサンプルです。
10+ //
11+ // チャネルの送受信の実装があるが、内部の処理結果によっては送信側がいなくなってしまうパターン。
12+ // 受信側のgoroutineが永遠に待ち続けるので終了しません。
13+ //
14+ // 解決方法としては、送信側が適切に使い終わったチャネルを閉じること。
15+ //
16+ // REFERENCES:
17+ // - https://betterprogramming.pub/common-goroutine-leaks-that-you-should-avoid-fe12d12d6ee
18+ func SenderAfterErrorCheck () error {
19+ var (
20+ ch = make (chan int )
21+ proc = func () bool {
22+ return false
23+ }
24+ fn = func (ch <- chan int ) {
25+ data := <- ch
26+ output .Stdoutl ("[recv]" , data )
27+ }
28+ )
29+
30+ go fn (ch )
31+
32+ if ! proc () {
33+ return errors .New ("this is dummy error" )
34+ }
35+
36+ //
37+ // 上でエラーが発生した場合、以下は処理されない。
38+ // なので、上で起動しているgoroutineは永遠に受信待機することになる。
39+ //
40+ ch <- 1
41+
42+ return nil
43+ }
You can’t perform that action at this time.
0 commit comments