为了账号安全,请及时绑定邮箱和手机立即绑定

从同一通道读取多个 Go 例程

从同一通道读取多个 Go 例程

Go
DIEA 2022-08-24 12:52:55
我遇到了控制通道(某种)问题。我的程序的本质:我不知道我将在运行时运行多少个 go 例程我需要在设定的时间重新启动这些 go 例程,但是,它们也可能出错(然后重新启动),因此它们的时间将无法预测。这些 go 例程会将消息放到单个通道上。所以我所做的是创建一个简单的随机消息生成器,将消息放到一个通道上。当计时器启动时(测试的随机持续时间),我将一条消息放到一个控制通道上,该通道是一个结构有效载荷,所以我知道有一个关闭信号,并且它是例行公事;实际上,在再次开始Go例程之前,我会做一些我需要做的其他事情。我的问题是:我在反射中收到控制消息。选择循环我没有(或无法)在我的randmsgs()循环中收到它因此,我无法阻止我的randmsgs()去例行公事。我相信我理解多个go例程可以从单个通道读取是正确的,因此我认为我误解了如何反映。选择大小写适合所有这些内容。我的代码:package mainimport (    "fmt"    "math/rand"    "reflect"    "time")type testing struct {    control bool    market  string}func main() {    rand.Seed(time.Now().UnixNano())    // explicitly define chanids for tests.    var chanids []string = []string{"GR I", "GR II", "GR III", "GR IV"}    stream := make(chan string)    control := make([]chan testing, len(chanids))    reflectCases := make([]reflect.SelectCase, len(chanids)+1)    // MAKE REFLECT SELECTS FOR 4 CONTROL CHANS AND 1 DATA CHANNEL    for i := range chanids {        control[i] = make(chan testing)        reflectCases[i] = reflect.SelectCase{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(control[i])}    }    reflectCases[4] = reflect.SelectCase{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(stream)}        // START GO ROUTINES    for i, val := range chanids {        runningFunc(control[i], val, stream, 1+rand.Intn(30-1))    }    // READ DATA    for {        o, recieved, ok := reflect.Select(reflectCases)        if !ok {            fmt.Println("You really buggered this one up...")        }        ty, err := recieved.Interface().(testing)        if err == true {            fmt.Printf("Read from: %v, and recieved close signal from: %s\n", o, ty.market)            // close control & stream here.        } else {            ty := recieved.Interface().(string)            fmt.Printf("Read from: %v, and recieved value from: %s\n", o, ty)        }    }}我为文字墙道歉,但我完全没有想法:(!
查看完整描述

1 回答

?
慕斯709654

TA贡献1840条经验 获得超5个赞

下半部分的频道与前半部分的频道相同。qcontrol[0...3]


您正在运行的通道也会从所有这些通道读取,而不会出现延迟。reflect.Select


我认为问题归结为您的运行速度太快并立即“窃取”所有通道输出。这就是为什么永远无法读取消息的原因。reflect.Selectrandmsgs


您会注意到,如果从 中删除默认大小写,则该函数能够(可能)从 中读取一些消息。randmsgsq


        select {

        case <-q:

            fmt.Println("Just sitting by the mailbox. :(")

            return

        }

这是因为现在它正在无延迟地运行,它总是在等待消息,因此有机会在比赛中击败。qreflect.Select


如果您从多个 goroutine 的同一通道读取,则传递的数据将简单地转到首先读取的任何 goroutine。


这个程序似乎只是一个实验/学习经验,但我会提供一些可能有帮助的批评。


同样,通常,如果两个goroutine执行不同的任务,则您不会有多个goroutine从同一通道读取。您正在创建一个大多数非确定性的竞赛,即哪个goroutine首先获取数据。


其次,这是一个常见的初学者的反模式,你应该避免选择:


for {

    select {

    case v := <-myChan:

        doSomething(v)

    default:

        // Oh no, there wasn't anything! Guess we have to wait and try again.

        time.Sleep(time.Second)

}

此代码是多余的,因为其行为方式已经达到这样的状态,即如果最初没有准备好任何案例,它将等到任何案例准备就绪,然后继续处理该案例。这有效地使您的选择循环变慢,但实际在通道上等待的时间更少(因为99.999...%的时间都花在 )。selectdefault: sleeptime.Sleep


查看完整回答
反对 回复 2022-08-24
  • 1 回答
  • 0 关注
  • 56 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信