golang中for循环遍历channel时需要注意的问题详解

前言

for循环是Go语言唯一的循环结构,最近在做一个基于RabbitMQ的应用,由于官方的qos没有golang的版本,所以出了一点问题。

问题代码如下:

_, ch, err := component.NewRabbitMQ()
if err != nil {
 panic(err)
}
if err := ch.Qos(10, 0, true); err != nil {
 panic(err)
}
msgs, err := ch.Consume("push", "", false, false, false, false, nil)
if err != nil {
 panic(err)
}
for m := range msgs {
 go func(d *amqp.Delivery) {
   defer func() { d.Ack(false) }
   // 处理消息
  }(&m)
 }

发现消费到10条消息,进程就退出了,但是exit code为0,表示系统是正常退出,由于做了日志记录可以确定消费了10条,所以初步确定是qos相关问题。

排查过程

  • 首先是把d的tag打印出来,发现全部是一样的,可以确定是重复的一条消息
  • 一开始想到可能是经典的go协程执行在for循环结束以后导致的,但是看我的代码不属于这种情况,有使用&m保证每一条消息都是不同循环传入的。所以判断可能是for循环的传递问题。
  • 确定方向之后开始写了一个测试项目用来验证我的想法是否正确。

测试代码

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 {
 fmt.Println(&v)
 }
}

执行输出

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

到这里才焕然大悟,for循环中,如果循环变量不是指针,那么每次的变量是同一个,不过值变了。,所以上例中的RabbitMQ go协程消费消息那里,需要直接传递值而不是指针,经过测试之后发现,问题确实解决了。

题外话

测试代码那里,如果不close掉channel是会发生死锁的,原因是 当for循环读完channel的10个值之后会继续尝试读取下一个,而由于channel为空又没关闭,会一直阻塞形成死锁

TOOD

研究RabbitMQ Consumer部分的源码来看看消费channel被关闭的问题。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对我们的支持。

(0)

相关推荐

  • Golang的循环中break和continue语句的用法讲解

    Go语言break语句 在Go编程语言中的break语句有以下两种用法: break语句用于在循环立即终止,程序控制继续下一个循环语句后面语句. 它可用于终止在switch语句的情况(case). 如果你正在使用嵌套循环(即,一个循环在另一个循环中),break语句将停止最内层循环的执行,并开始执行的下一行代码的程序段之后. 语法 在Go break语句的语法如下: break; 流程图: 例子: 复制代码 代码如下: package main import "fmt" func ma

  • 深入解析Go语言中for循环的写法

    for循环是一个循环控制结构,可以有效地编写需要执行的特定次数的循环. 语法 for循环在Go编程语言中的语法是: 复制代码 代码如下: for [condition |  ( init; condition; increment ) | Range] {    statement(s); } 下面是控制在一个流程的for循环: 如果condition是可用的,那么对于循环只要条件为真时执行. 如果for子句是( init; condition; increment ) 存在则 初始化(init

  • Go语言流程控制之goto语句与无限循环

    goto语句 在Go编程语言中的goto语句提供无条件跳转从跳转到标记声明的功能. 注意:使用goto语句是高度劝阻的在任何编程语言,因为它使得难以跟踪程序的控制流程,使程序难以理解,难以修改.使用一个goto任何程序可以改写,以便它不需要goto. 语法 转到goto语句的语法如下: 复制代码 代码如下: goto label; .. . label: statement; 在这里,标签(label)可以是除去关键字任何纯文本,它可以在任何地方设置在Go程序的上方或下方,以使用goto语句.

  • Golang常见错误之值拷贝和for循环中的单一变量详解

    前言 golang(中文名:go语言)是谷歌2009发布的第二款开源编程语言.Go语言专门针对多处理器系统应用程序的编程进行了优化,使用Go编译的程序可以媲美C或C++代码的速度,而且更加安全.支持并行进程..如果你想知道得更多,请移步至官网golang官网 在 Go 中函数的调用是值拷贝 copy value,而且在 for 循环中 v 的变量始终是一个变量.如果 v 是 pointer,print 这个 method 接收的是指针的拷贝,for 循环体中每次迭代 v 的 pointer va

  • golang语言中for循环语句用法实例

    本文实例讲述了golang语言中for循环语句用法.分享给大家供大家参考.具体分析如下: for循环是用来遍历数组或数字的.用for循环遍历字符串时,也有 byte 和 rune 两种方式.第一种为byte,第二种rune. 复制代码 代码如下: package main import ( "fmt" ) func main() { s := "abc汉字" for i := 0; i < len(s); i++ { fmt.Printf("%c,&

  • Golang实现for循环运行超时后自动退出的方法

    前言 for循环是用来遍历数组或数字的.用for循环遍历字符串时,也有 byte 和 rune 两种方式.第一种为byte,第二种rune.下面话不多说了,来一起看看详细的介绍吧. Golang实现for循环 package main import "fmt" func main() { sum := 0 for i := 0; i < 10; i++ { sum += i } fmt.Println(sum) } 跟C语言中一样,可以让前置.后置语句为空. package ma

  • 详解golang避免循环import问题(“import cycle not allowed”)

    前言 golang不允许循环import package ,如果检测到 import cycle ,会在编译时报错,通常import cycle是因为设计错误或包的规划问题. 以下面的例子为例,package a依赖package b,同事package b依赖package a package a import ( "fmt" "github.com/mantishK/dep/b" ) type A struct { } func (a A) PrintA() {

  • Go语言模拟while语句实现无限循环的方法

    本文实例讲述了Go语言模拟while语句实现无限循环的方法.分享给大家供大家参考.具体实现方法如下: 这段代码把for语句当成C语言里的while(true)用实现无限循环 复制代码 代码如下: package main import "fmt" func main() {     sum := 0     for {         sum ++         if sum > 10{             break         }else{            

  • golang中for循环遍历channel时需要注意的问题详解

    前言 for循环是Go语言唯一的循环结构,最近在做一个基于RabbitMQ的应用,由于官方的qos没有golang的版本,所以出了一点问题. 问题代码如下: _, ch, err := component.NewRabbitMQ() if err != nil { panic(err) } if err := ch.Qos(10, 0, true); err != nil { panic(err) } msgs, err := ch.Consume("push", "&quo

  • Golang中优秀的消息队列NSQ基础安装及使用详解

    前言 NSQ是Go语言编写的,开源的分布式消息队列中间件,其设计的目的是用来大规模地处理每天数以十亿计级别的消息.NSQ 具有分布式和去中心化拓扑结构,该结构具有无单点故障.故障容错.高可用性以及能够保证消息的可靠传递的特征,是一个成熟的.已在大规模生成环境下应用的产品. 背景介绍 在服务器最开始的时候,基本上在一台主机上就能解决大部分问题,所以一般架构设计如下: 但是,突然某一天,来了一个新需求,我们服务器上不只是简单的储存一些文本信息,我们需要储存图片甚至视频,显然直接在一台主机上再部署一个

  • Golang中for循环的用法示例详解

    目录 Golang中for循环的用法 for循环 基本语法 注意事项和使用细节 Golang中for循环的用法 for循环 就是让一段代码循环的执行. 基本语法 for循环变量初始化:循环条件:循环变量迭代{ 循环操作(语句) } package main import "fmt" func main(){ for i := 1; i <= 10; i++ { fmt.Println("666",i) } } for循环的四个要素: 1.循环变量初始化 2.循

  • 浅析vue中常见循环遍历指令的使用 v-for

    vue中循环遍历使用的指令是v-for 1.v-for遍历数组 (1)value in arr 遍历数组中的元素 (2)(value,index) in arr 遍历数组中的元素和数组下标 运行代码: <body> <div class="box"> <ul> <li v-for="value in arr">{{value}}</li><br> <li v-for="(valu

  • 聊聊python中的循环遍历

    python之循环遍历 关于循环遍历大家都知道,不外乎for和while,今天我在这写点不一样的循环和遍历.在实践中有时会遇到删除列表中的元素,那么循环遍历列表删除指定元素该怎么做呢? 还是直接上代码看案例吧: import time # 删除下面列表中所有张姓元素,输出的结果应该是['李老大','李老二'] lst = ['张老大', '张老二', '李老大', '张老三', '李老二']*10000 # 直接for循环遍历列表,remove需要删除的元素 def del1(lst): for

  • C#中Foreach循环遍历的本质与枚举器详解

    目录 前言 1.创建一个控制台应用程序 2.编写测试代码并分析 3.总结 前言 对于C#里面的Foreach学过 语言的人都知道怎么用,但是其原理相信很多人和我一样都没有去深究.刚回顾泛型讲到枚举器让我联想到了Foreach的实现,所以进行一番探究,有什么不对或者错误的地方大家多多斧正. 1.创建一个控制台应用程序 2.编写测试代码并分析 在Program类中写一个foreach循环 class Program { static void Main(string[] args) { List p

  • Java中Map循环遍历的五种方法实现

    目录 1.创建一个Enum 2.开始遍历 方法一 方法二 方法三 方法四 方法五 因为Map比较常用,所以今天来总结下Map取值比较常用的几种遍历方法. 1.创建一个Enum public enum FactoryStatus {     BAD(0,"ou"),     GOOD(1,"yeah");     private int status;     private String description;     FactoryStatus(int stat

  • ASP.NET MVC中使用jQuery时的浏览器缓存问题详解

    介绍 尽管jQuery在浏览器ajax调用的时候对缓存提供了很好的支持,还是有必要了解一下如何高效地使用http协议. 首先要做的事情是在服务器端支持HTTP GET,定义不同的URL输出不同的数据(MVC里对应的就是action).如果要使用同一个地址获取不同的数据,那就不对了,一个HTTP POST也不行因为POST不能被缓存.许多开发人员使用POST主要有2个原因:明确了数据不能被缓存,或者是避免JSON攻击(JSON返回数组的时候可以被入侵). 缓存解释 jQuery全局对象里的ajax

  • Android 中Crash时如何获取异常信息详解及实例

    Android 中Crash时如何获取异常信息详解 前言: 大家都知道,Android应用不可避免的会发生crash,无论你的程序写的多完美,总是无法完全避免crash的发生,可能是由于Android系统底层的bug,也可能是由于不充分的机型适配或者是糟糕的网络状况.当crash发生时,系统会kill掉你的程序,表现就是闪退或者程序已停止运行,这对用户来说是很不友好的,也是开发者所不愿意看到的,更糟糕的是,当用户发生了crash,开发者却无法得知程序为何crash,即便你想去解决这个crash,

  • Java 中的vector和list的区别和使用实例详解

    要了解vector,list,deque.我们先来了解一下STL. STL是Standard Template Library的简称,中文名是标准模板库.从根本上说,STL是一些容器和算法的集合.STL可分为容器(containers).迭代器(iterators).空间配置器(allocator).配接器(adapters).算法(algorithms).仿函数(functors)六个部分.指针被封装成迭代器,这里vector,list就是所谓的容器. 我们常常在实现链表,栈,队列或者数组时,

随机推荐