Я пытаюсь написать прослушиватель событий и попытаться контролировать поток состояния внутри слушателя. Я знал, что пропустил какой-то принцип использования канала, и код может выглядеть глупо. Тем не менее, я буду признателен, если кто-то может помочь мне понять, что моя ошибка и как ее улучшить.Путаница о потоке управления каналом
Этот код не может работать:
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")
}
Почему не может вызвать другой канал в один и тот же канальный обработчик уровня?
'this.exit <-true' блокирует работы goroutine в то время как он ожидает goroutine к получать от 'this.exit'. Когда вы 'this.exit <-true' в' handler() 'вызывается из' Run() ',' Run() 'goroutine, который обычно получает' this.exit', застревает, так что ничего не получится это 'истина', поэтому вы получаете эту ошибку. Другим изменением для работы над ним было бы просто 'go this.handler()' вместо 'this.handler()'; Я действительно не знаю, что вы пытаетесь сделать здесь, поэтому я не знаю, что имеет смысл. – twotwotwo
Сокращенная версия: каналы отправляются обычно * между * goroutines. Никогда не делайте блокирующий канал, отправляемый из той же goroutine, которая должна выполнять соответствующий прием канала. – twotwotwo