简体   繁体   English

有时 goroutine 不会从通道获取事件数据

[英]Sometimes goroutine NOT get event data from channel

My issue is sometimes goroutine NOT get event data from reg.eventCh我的问题有时是 goroutine 没有从 reg.eventCh 获取事件数据

NO exit log print, this goroutine is NOT exit, is running.没有退出日志打印,这个 goroutine 不是退出,正在运行。

reg.eventCh channel is NOT closed, log can print length increment. reg.eventCh通道未关闭,日志可以打印长度增量。

Logs shows:日志显示:

reg.eventCh <- event, count: 1
event is coming

reg.eventCh <- event, count: 0  (why count is 0? log print after data in channel)
event is coming

reg.eventCh <- event, count: 1

reg.eventCh <- event, count: 2
.
.
.
reg.eventCh <- event, count: 999

reg.eventCh <- event, count: 1000

log shows DO NOT get event data from reg.eventCh, belows is my codes:日志显示 DO NOT get event data from reg.eventCh,以下是我的代码:

reg := &Reg{}
reg.exitCh = make(chan *demo.Exit)
reg.eventCh = make(chan *demo.Event, 1000)

go reader(reg)

// other goroutine will writer event to reg.eventCh like:

reg.eventCh <- event
log.Println("reg.eventCh <- event, count:",len(reg.eventCh))


func reader(reg *Reg) {
    for {
        select {
            case event := <-reg.eventCh:
                log.Println("event is coming")
                handler(event)
            case exit := reg.exitCh:
                log.Println("exit")
                return
        }
    }
}

Is my codes something wrong?我的代码有问题吗?

any help will be appreciated,任何帮助将不胜感激,

Thanks,谢谢,

Jimmy吉米

demo code:演示代码:

package main

import (
    "log"
    "math/rand"
    "time"
)

type Event struct {
    testStr string
}

type Exit struct {
    testStr string
}

type Reg struct {
    des     string
    eventCh chan *Event
    exitCh  chan *Exit
}

// this demo code like my issue
// this issue is sometimes case event := <-reg.eventCh NOT work in go reader()
func main() {
    reg := &Reg{}
    reg.des = "sometime not read from reg.eventCh"
    reg.eventCh = make(chan *Event, 1000)
    reg.exitCh = make(chan *Exit)

    // read data from channel
    go reader(reg)

    // simulate data: write in channel
    for i := 0; i < 10; i++ {
        go writer(reg)
    }

    select {}
}

func writer(reg *Reg) {
    for {
        time.Sleep(time.Duration(rand.Intn(500)) * time.Millisecond)
        event := new(Event)
        event.testStr = "1"
        reg.eventCh <- event
        log.Println("reg.eventCh <- event, channel count:", len(reg.eventCh))
    }
}

func reader(reg *Reg) {
    for {
        select {
        case event := <-reg.eventCh:
            log.Println("event is coming, channel count:", len(reg.eventCh))
            handler(event)
        case exit := <-reg.exitCh:
            log.Println("goroutine exit: ", exit)
            return
        }
    }
}

func handler(e *Event) {
    // logic codes
}

need time to repro this issue。需要时间重现这个问题。

Your code has some errors, It dont send data to exitCh.您的代码有一些错误,它不会向 exitCh 发送数据。 it dont has stop condition and deadlock block.它没有停止条件和死锁块。 I will share my answer by answering 3 questions I raised.我将通过回答我提出的 3 个问题来分享我的答案。

Question#1 : why count is 0? log print after data in channel问题#1why count is 0? log print after data in channel why count is 0? log print after data in channel

len(channel) is only useful to know how much data is currently available. len(channel)仅用于了解当前可用的数据量。 If the recipient has already received the data, it will always be 0.如果接收方已经收到数据,则始终为 0。

Question#2 : why use select like exit control?问题#2 :为什么像退出控制一样使用 select?

you could use <-context.Done() or others code more idiomatic.您可以使用<-context.Done()或其他更惯用的代码。

Question#3 : why there is no data for exitCh?问题#3 :为什么没有exitCh 的数据?

apparently you created an exitch to get out of the loop, but it's not working显然你创建了一个退出循环,但它不起作用

Code sugestion:代码建议:

package main

import (
    "context"
    "fmt"
    "log"
)

var (
    ctx, cancel = context.WithCancel(context.Background())
)

type Event struct {
    testStr string
}

type Exit struct {
    testStr string
}

type Reg struct {
    des     string
    eventCh chan *Event
    exitCh  chan *Exit
}

// this demo code like my issue
// this issue is sometimes case event := <-reg.eventCh NOT work in go reader()
func main() {
    //
    reg := &Reg{}
    reg.des = "sometime not read from reg.eventCh"
    reg.eventCh = make(chan *Event, 1000)
    reg.exitCh = make(chan *Exit)

    // read data from channel
    go reader(reg)

    // simulate data: write in channel
    for i := 0; i < 10; i++ {
        go writer(reg, fmt.Sprintf("gorouinte-%d", i))
    }
    // notify exit
    <-ctx.Done()
}

func writer(reg *Reg, tname string) {
    for /* infinity loop */ {
        // time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond)
        event := new(Event)
        event.testStr = "1"
        reg.eventCh <- event
        log.Println("reg.eventCh <- event, channel count:", len(reg.eventCh))
        // simulates stop condition
        if len(reg.eventCh) == 1000 {
            reg.exitCh <- &Exit{"exit now!"}
            log.Printf("stop write loop in routine %s\n", tname)
            return
        }
    }
}

func reader(reg *Reg) {
    for {
        select {
        case event := <-reg.eventCh:
            log.Println("event is comming, channel count:", len(reg.eventCh))
            handler(event)
        case exit := <-reg.exitCh:
            log.Println("goroutine exit: ", exit)
            cancel() // used to exit this program
            return
        }
    }
}

func handler(e *Event) {
    // logic codes
}

Playground demo游乐场演示

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM