gpt4 book ai didi

go - 混淆 channel 控制流

转载 作者:数据小太阳 更新时间:2023-10-29 03:29:23 28 4
gpt4 key购买 nike

我正在尝试编写一个事件监听器并尝试控制监听器内部的状态流。我知道我错过了 channel 使用的一些原则,代码可能看起来很愚蠢。但是,如果有人可以帮助我了解我的错误是什么以及如何改进它,我将不胜感激。

此代码无法运行:

package main

import (
"fmt"
"time"
)

type A struct {
count int
ch chan bool
exit chan bool
}

func (this *A) Run() {
for {
select {
case <-this.ch:
this.handler()
case <-this.exit:
return
default:
time.Sleep(20 * time.Millisecond)
}
}
}

func (this *A) handler() {
println("hit me")
if this.count > 2 {
this.exit <- true
}
fmt.Println(this.count)
this.count += 1
}

func (this *A) Hit() {
this.ch <- true
}

func main() {
a := &A{}
a.ch = make(chan bool)
a.exit = make(chan bool)

go a.Hit()
go a.Hit()
go a.Hit()
go a.Hit()
a.Run()

fmt.Println("s")
}

它引发错误:

hit me
0
hit me
1
hit me
2
hit me
fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan send]:
main.(*A).handler(0x2101bf000)
/Users/yeer/go/src/github.com/athom/practice/channel-controll.go:31 +0x60
main.(*A).Run(0x2101bf000)
/Users/yeer/go/src/github.com/athom/practice/channel-controll.go:19 +0x66
main.main()
/Users/yeer/go/src/github.com/athom/practice/channel-controll.go:50 +0xed
exit status 2

但是,这段代码有效:

package main

import (
"fmt"
"time"
)

type A struct {
count int
ch chan bool
exit chan bool
}

func (this *A) Run() {
for {
select {
case <-this.ch:
this.handler()
case <-this.exit:
return
default:
time.Sleep(20 * time.Millisecond)
}
}
}

func (this *A) handler() {
println("hit me")
}

func (this *A) Hit() {
this.ch <- true
if this.count > 2 {
this.exit <- true
}
fmt.Println(this.count)
this.count += 1
}

func main() {
a := &A{}
a.ch = make(chan bool)
a.exit = make(chan bool)

go a.Hit()
go a.Hit()
go a.Hit()
go a.Hit()
a.Run()

fmt.Println("s")
}

为什么不能在同级 channel 处理程序中触发另一个 channel ?

最佳答案

您的代码死锁是因为当您在退出 channel 上发送时 this.exit <- true这是来自您从该 channel 接收到的同一个 goroutine,并且永远无法完成。

可能最明智的做法是用 bool 标志替换退出 channel 。如果你这样做,那么它工作正常。

Play

type A struct {
count int
ch chan bool
exit bool
}

func (this *A) Run() {
for !this.exit {
select {
case <-this.ch:
this.handler()
default:
time.Sleep(20 * time.Millisecond)
}
}
}

func (this *A) handler() {
println("hit me")
if this.count > 2 {
this.exit = true
}
fmt.Println(this.count)
this.count += 1
}

func (this *A) Hit() {
this.ch <- true
}

func main() {
a := &A{}
a.ch = make(chan bool)

go a.Hit()
go a.Hit()
go a.Hit()
go a.Hit()
a.Run()

fmt.Println("Done")
}

另一种选择是使用 go this.handler() 在自己的 go 例程中运行每个处理程序

Play

func (this *A) Run() {
for {
select {
case <-this.ch:
go this.handler() // add go here
case <-this.exit:
return
default:
time.Sleep(20 * time.Millisecond)
}
}
}

最后你可以缓冲退出 channel

Play

func main() {
a := &A{}
a.ch = make(chan bool)
a.exit = make(chan bool, 5) // add buffer here

go a.Hit()
go a.Hit()
go a.Hit()
go a.Hit()
a.Run()

fmt.Println("Done")
}

关于go - 混淆 channel 控制流,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20027901/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com