SoFunction
Updated on 2025-03-04

Detailed explanation of the issues that need to be paid attention to when traversing channel for loop in golang

Preface

For loop is the only loop structure in Go language. Recently, I am working on a RabbitMQ-based application. Since the official qos does not have a golang version, something went wrong.

The problem code is as follows:

_, ch, err := ()
if err != nil {
 panic(err)
}
if err := (10, 0, true); err != nil {
 panic(err)
}
msgs, err := ("push", "", false, false, false, false, nil)
if err != nil {
 panic(err)
}
for m := range msgs {
 go func(d *) {
   defer func() { (false) }
   // Process messages  }(&m)
 }

When you find that 10 messages are consumed, the process exits, but the exit code is 0, which means that the system exits normally. Since logging can be done, it can be determined that 10 messages have been consumed, so it is initially determined that it is a QOS-related problem.

Troubleshooting process

  • First, print out the tag of d and find that it is all the same. You can confirm that it is a duplicate message
  • At first I thought that it might be caused by the classic go coroutine execution after the for loop ends, but my code does not belong to this situation. I have used &m to ensure that each message is passed in different loops. So the judgment may be a problem with the delivery of the for loop.
  • After determining the direction, I started writing a test project to verify that my idea was correct.

Test code

package main
import "fmt"
func main() {
 ch := make(chan int, 10)
 for i := 0; i < 10; i++ {
 ch <- i
 }
 close(ch)
 for v := range ch {
 (&v)
 }
}

Execute output

0xc420086008
0xc420086008
0xc420086008
0xc420086008
0xc420086008
0xc420086008
0xc420086008
0xc420086008
0xc420086008
0xc420086008

Only then did I realize that in the for loop, if the loop variable is not a pointer, then the variable is the same every time, but the value has changed. , so in the RabbitMQ go coroutine consumption message in the above example, it is necessary to directly pass the value instead of a pointer. After testing, it was found that the problem was indeed solved.

Off topic

In the test code, if the channel is not closed, a deadlock will occur. The reason is that after the for loop reads the 10 values ​​of the channel, it will continue to try to read the next one. Because the channel is empty and not closed, it will keep blocking and forming a deadlock.

TOOD

Study the source code of RabbitMQ Consumer part to see the problem of consumer channel being closed.

Summarize

The above is the entire content of this article. I hope that the content of this article has certain reference value for everyone's study or work. If you have any questions, you can leave a message to communicate. Thank you for your support.