[英]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
问题#1 :
why 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
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.