Golang 为什么这个超时方案不起作用?
Golang why doesn't this timeout scheme work?
所以我有这个用于发送消息的代码块。传递给 c.outChan 的消息被传输,如果在 return 中收到确认,则 "true" 将通过 c.buffer[nr].signaler 通道传递。这似乎工作正常,但如果消息被丢弃(没有收到确认),而不是到达超时打印,它只是停止,我不知道为什么。这是代码:
func (c *uConnection) send(nr uint32) {
//transmitt message
c.outChan <- c.buffer[nr].msg
timeout := make(chan bool, 1)
go func() {
timeoutTimer := time.After(c.retransTime)
<-timeoutTimer
timeout <- true
}()
switch {
case <-c.buffer[nr].signaler:
fmt.Printf("Ack confirmed: %v\n", nr)
case <-timeout:
fmt.Println("-----------timeout-----------\n")
//resending
c.send(nr)
}
}
我做错了什么?
您的频道正在使用开关,但您需要 select。该开关对通道一无所知,而只是尝试评估 select 之前的 case 语句中的表达式。您当前的代码等同于:
func (c *uConnection) send(nr uint32) {
//transmitt message
c.outChan <- c.buffer[nr].msg
timeout := make(chan bool, 1)
go func() {
timeoutTimer := time.After(c.retransTime)
<-timeoutTimer
timeout <- true
}()
tmp1 := <-c.buffer[nr].signaler // this will block
tmp2 := <-timeout
switch {
case tmp1 :
fmt.Printf("Ack confirmed: %v\n", nr)
case tmp2 :
fmt.Println("-----------timeout-----------\n")
//resending
c.send(nr)
}
}
您的代码应如下所示(使用 select 而不是 switch):
func (c *uConnection) send(nr uint32) {
//transmitt message
c.outChan <- c.buffer[nr].msg
timeout := make(chan bool, 1)
go func() {
timeoutTimer := time.After(c.retransTime)
<-timeoutTimer
timeout <- true
}()
select {
case <-c.buffer[nr].signaler:
fmt.Printf("Ack confirmed: %v\n", nr)
case <-timeout:
fmt.Println("-----------timeout-----------\n")
//resending
c.send(nr)
}
}
另外,你的超时 goroutine 是不必要的。您可以直接在 time.After 上等待,而不是调用 time.After,等待通道然后发送到您自己的超时通道。示例:
func (c *uConnection) send(nr uint32) {
//transmitt message
c.outChan <- c.buffer[nr].msg
select {
case <-c.buffer[nr].signaler:
fmt.Printf("Ack confirmed: %v\n", nr)
case <-time.After(c.retransTime):
fmt.Println("-----------timeout-----------\n")
//resending
c.send(nr)
}
}
这样更快、更清晰并且占用更少的内存。
所以我有这个用于发送消息的代码块。传递给 c.outChan 的消息被传输,如果在 return 中收到确认,则 "true" 将通过 c.buffer[nr].signaler 通道传递。这似乎工作正常,但如果消息被丢弃(没有收到确认),而不是到达超时打印,它只是停止,我不知道为什么。这是代码:
func (c *uConnection) send(nr uint32) {
//transmitt message
c.outChan <- c.buffer[nr].msg
timeout := make(chan bool, 1)
go func() {
timeoutTimer := time.After(c.retransTime)
<-timeoutTimer
timeout <- true
}()
switch {
case <-c.buffer[nr].signaler:
fmt.Printf("Ack confirmed: %v\n", nr)
case <-timeout:
fmt.Println("-----------timeout-----------\n")
//resending
c.send(nr)
}
}
我做错了什么?
您的频道正在使用开关,但您需要 select。该开关对通道一无所知,而只是尝试评估 select 之前的 case 语句中的表达式。您当前的代码等同于:
func (c *uConnection) send(nr uint32) {
//transmitt message
c.outChan <- c.buffer[nr].msg
timeout := make(chan bool, 1)
go func() {
timeoutTimer := time.After(c.retransTime)
<-timeoutTimer
timeout <- true
}()
tmp1 := <-c.buffer[nr].signaler // this will block
tmp2 := <-timeout
switch {
case tmp1 :
fmt.Printf("Ack confirmed: %v\n", nr)
case tmp2 :
fmt.Println("-----------timeout-----------\n")
//resending
c.send(nr)
}
}
您的代码应如下所示(使用 select 而不是 switch):
func (c *uConnection) send(nr uint32) {
//transmitt message
c.outChan <- c.buffer[nr].msg
timeout := make(chan bool, 1)
go func() {
timeoutTimer := time.After(c.retransTime)
<-timeoutTimer
timeout <- true
}()
select {
case <-c.buffer[nr].signaler:
fmt.Printf("Ack confirmed: %v\n", nr)
case <-timeout:
fmt.Println("-----------timeout-----------\n")
//resending
c.send(nr)
}
}
另外,你的超时 goroutine 是不必要的。您可以直接在 time.After 上等待,而不是调用 time.After,等待通道然后发送到您自己的超时通道。示例:
func (c *uConnection) send(nr uint32) {
//transmitt message
c.outChan <- c.buffer[nr].msg
select {
case <-c.buffer[nr].signaler:
fmt.Printf("Ack confirmed: %v\n", nr)
case <-time.After(c.retransTime):
fmt.Println("-----------timeout-----------\n")
//resending
c.send(nr)
}
}
这样更快、更清晰并且占用更少的内存。