golangでのchannelのエラー使用を一度メモします

1962 ワード

この間、プロジェクトの中で問題があって、テストの時までgoroutineがまだ走っていることに気づいて、何だか間違っていて、demoを書いて走って発見して、やはりgoroutineが止まっていないことがあって、くだらないことは多く言わないで、直接コードに行きます
package main

import (
    "fmt"
    "time"
)

type Adapter struct {
    stop chan struct{}
}

func main() {
    ch := make(chan struct{})

    a := Adapter{stop: make(chan struct{})}
    go a.tick()
    time.Sleep(3 * time.Second)
    close(a.stop)
    a.stop = nil
    

結局、そうです...
index: 0
index: 1
index: 2
index: 3
index: 4
index: 5
index: 6
index: 7
index: 8
index: 9
index: 10
index: 11
index: 12
index: 13
index: 14
index: 15
index: 16
index: 17
index: 18
index: 19
index: 20
...

tick stopは印刷されていませんか?このtick協程は止まらずtime.Tickというchannelはずっと実行されています.
次にclose(a.stop)の後にコードtimeを挿入した.Sleep(1 time.Millisecond)*奇跡が起こった
package main

import (
    "fmt"
    "time"
)

type Adapter struct {
    stop chan struct{}
}

func main() {
    ch := make(chan struct{})

    a := Adapter{stop: make(chan struct{})}
    go a.tick()
    time.Sleep(3 * time.Second)
    close(a.stop)
    time.Sleep(1 * time.Millisecond)
    a.stop = nil
    
index: 0
index: 1
index: 2
tick stop


このようにすると、close(a.stop)によってchannel信号がキャプチャされ、この方法が繰り返し呼び出されるとエラーが発生するという問題がある.
panic: close of closed channel
goroutine 1 [running]:

改善

package main

import (
    "fmt"
    "log"
    "time"
)

type Adapter struct {
    stop chan struct{}
}

func main() {
    ch := make(chan struct{})
    a := Adapter{stop: make(chan struct{})}
    go a.tick()
    time.Sleep(3 * time.Second)
    err := a.closeTick()
    if err!=nil{
        log.Fatal(err)
    }
    //test do again
    err = a.closeTick()
    if err!=nil{
        log.Fatal(err)
    }
    

ここでは外部で手動close channelを利用するのではなく,channelに匿名構造体を伝達しstopに信号を受信させtickコヒーレンスを停止させる