【记录一个伟大的坑】for 循环写进chan局部变量指针

本文记录了一次由于在for循环中使用同一局部变量指针写入chan导致的严重问题。作者在处理大量数据时,由于将结构体初始化放在循环外部,使得所有协程都在操作同一内存地址,引发数据重复。解决方案是将结构体初始化放入循环体内,确保每次循环写入chan的是新的地址,从而避免了问题。

敲代码三年了,刚从Java开始,我就一直秉持着当使用循环时我尽量把临时的局部变量定义再循环体外,因为这样可以节约内存的开销,毕竟没声明一个变量,系统都要给他分配地址,都要消耗内存,请看下面代码:

	for i := 0; i < 100; i++ {
		var tmp = strconv.Itoa(i)
		fmt.Println(&tmp,":",tmp)
	}

	fmt.Println("*****************************************")
	var tmp string
	for i := 0; i < 100; i++ {
		tmp = strconv.Itoa(i)
		fmt.Println(&tmp,":",tmp)
	}

打印:

在这点代码里,上面的for循环会为tmp内存开辟一百个地址!而下面的始终只分配了一个地址,变化的只是值。

为了代码的质量,我一直把变量的定义放在循环体外。直到今天,直到刚刚,昨晚我用go去读取一个本地的大数据文本,是一个1.5G的txt文件,我要把里面的数据读取到MySQL中去,昨天就写好了,可是执行后我发现总是有重复的写入!我又把业务逻辑梳理了一遍,一遍又一遍,从打开数据库建立连接,打开大数据文本,bufio的读取,数据的截取,转换go数据,写入通道(因为数据量庞大,我开了1000的并发协程,把通道的容量设定为10e6)……一遍又一遍的把业务逻辑梳理了,最后我坚

在Go语言中,使用`for...range`遍历channel时,通常只有在channel关闭后循环才会结束。因为`for...range`会持续从channel中接收数据,直到channel关闭且没有数据剩余。以下是一个示例代码: ```go package main import ( "fmt" "time" ) func main() { ch := make(chan int) // 启动一个goroutine向channel写入数据 go func() { for i := 0; i < 3; i++ { ch <- i time.Sleep(time.Second) } close(ch) }() // 使用for...range遍历channel for value := range ch { fmt.Printf("Read a value from ch: %d\n", value) } fmt.Println("Loop ended.") } ``` 在这个例子中,`for...range`循环会持续从channel中接收数据,直到channel被关闭。 然而,如果不使用`for...range`,而是使用普通的`for`循环结合`<-ch`操作符,就可以在不关闭channel的情况下控制循环的结束。示例如下: ```go package main import ( "fmt" "time" ) func main() { ch := make(chan int) // 启动一个goroutine向channel写入数据 go func() { for i := 0; i < 3; i++ { ch <- i time.Sleep(time.Second) } // 这里不关闭channel }() // 使用普通for循环和<-ch操作符 for { select { case value, ok := <-ch: if ok { fmt.Printf("Read a value from ch: %d\n", value) } else { fmt.Println("Channel is closed.") break } case <-time.After(2 * time.Second): fmt.Println("Timeout, exiting loop.") break } } fmt.Println("Loop ended.") } ``` 在这个例子中,使用`select`语句结合`time.After`设置了一个超时机制,当2秒内没有从channel接收到数据时,就会退出循环,而不需要关闭channel。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值