【转】Golang关于channel传递引用引发的坑
原文: https://studygolang.com/articles/12310/comment/17923
--------------------------------------------------------------------------------------
Time won't go back I won't turn back.
时光不会倒着走,我也不会再回头。
其实这个问题其实是出现在引用类型( 此处是slice )上, 这个是 slice 的数据结构,它很简单,一个指向真实 array 地址的指针 ptr ,slice 的长度 len 和容量 cap 。

结构图解1

每次cap改变的时候指向array内存的指针都在变化, 在实际使用中,我们最好事先预期好一个cap,这样在使用append的时候可以避免反复重新分配内存复制之前的数据,减少不必要的性能消耗。
现在上实例,来看看坑所在:
package main
import "fmt"
import "time"
func main() {
ch := make(chan []byte, 10)
go func() {
for {
select {
case data := <-ch:
fmt.Println(string(data))
}
}
}()
data := make([]byte, 0, 32)
data = append(data, []byte("bbbbbbbbbb")...)
ch <- data
// fmt.Printf("%p\n", data)
data = data[:0]
// fmt.Printf("%p\n", data)
data = append(data, []byte("aaa")...)
ch <- data
time.Sleep(time.Second * 5)
}
预测的运行结果:
bbbbbbbbbb
aaa
但是肯定是有坑的:

前面新起了一个协程来等待通道接受信息, 主进程继续执行, 当data传递给了通道之后, 立刻修改了data指向数组的值(第二次append), 所以通道第一次接收的值就已经改变了, 因为我们传递的是引用,不是值类型。
解决方案呢就是加锁 或者新变量拷贝。
【转】Golang关于channel传递引用引发的坑的更多相关文章
- 深入学习golang(2)—channel
Channel 1. 概述 “网络,并发”是Go语言的两大feature.Go语言号称“互联网的C语言”,与使用传统的C语言相比,写一个Server所使用的代码更少,也更简单.写一个Server除了网 ...
- golang的Channel
golang的Channel Channel 是 golang 一个非常重要的概念,如果你是刚开始使用 golang 的开发者,你可能还没有真正接触这一概念,本篇我们将分析 golang 的Chann ...
- Golang 入门 : channel(通道)
笔者在<Golang 入门 : 竞争条件>一文中介绍了 Golang 并发编程中需要面对的竞争条件.本文我们就介绍如何使用 Golang 提供的 channel(通道) 消除竞争条件. C ...
- 传递引用类型参数的两种方式(转自 MSDN)
引用类型的变量不直接包含其数据:它包含的是对其数据的引用.当通过值传递引用类型的参数时,有可能更改引用所指向的数据,如某类成员的值(更改属性的值),但是无法更改引用本身的值:也就是说,不能使用相同的引 ...
- 传递引用类型参数(ref)
引用类型的变量不直接包含其数据:它包含的是对其数据的引用. 当通过值传递引用类型的参数时,有可能更改引用所指向的数据,如某类成员的值. 但是无法更改引用本身的值:也就是说,不能使用相同的引用为新类分配 ...
- JAVA一个关于传递引用的测试
以下测试主要为了说明:对传递对象或传递引用进行修改,对最终值的影响情况 public class PassTest { @Before public void setUp() thro ...
- thread - 传递引用参数
当给 thread 的执行函数传递指针参数时,没有任何问题,但是如果想传递引用,按照普通函数的调用方法会遇到编译失败: #include <iostream> #include <t ...
- 对象引用 方法传参 值传递 引用传递 易错点 MD
Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...
- 《从零开始学Swift》学习笔记(Day 20)——函数中参数的传递引用
原创文章,欢迎转载.转载请注明:关东升的博客 参数的传递引用 类是引用类型,其他的数据类型如整型.浮点型.布尔型.字符.字符串.元组.集合.枚举和结构体全部是值类型. 有的时候就是要将一个值类型参数以 ...
随机推荐
- ng接口API开发文档
接口版本:v1 接口协议:请商户对接使用对应的转账接口API和免转接口API,商户只能使用菜单对应的API,否则接口会调用失败.左侧菜单未注明的接口免转钱包和转账钱包可以共同使用所有采集均按照北京时间 ...
- ROS学习(二)运行keyboard
1.ssh连接机器人 ./dora*.sh 启动roscore,相当于启动ros系统 roscore 2.另启终端,也就意味着重新ssh连接机器人, ./dora*.sh 运行wheel驱动 rosr ...
- springboot集成elk 一: springboot + Elasticsearch
1.ELK介绍 1> Elasticsearch是实时全文搜索和分析引擎, 提供搜集.分析.存储数据三大功能: 是一套开放REST和JAVA API等结构提供高效搜索功能,可扩展的分布式系统. ...
- Fiddler之手机抓包
1.Fiddle设置端口,Tools->Options->Connections, 2.手机设置代理服务器: 注意:要保证手机和PC电脑IP在同一个网段(或者同一个网关) (1).安卓手机 ...
- 从 select ... for update来分析mysql的锁
一 mysql的悲观锁 - 以行锁做示例 每次拿数据的时候都认为别的线程会修改数据,所以每次拿数据的时候都会给数据上锁.上锁之后,当别的线程想要拿数据时,就会阻塞.直到给数据上锁的线程将事务提交或者回 ...
- Linux下使用Vim粘贴文本错乱问题解决
在使用vim进行文档操作时,经常需要进行复制粘贴,在粘贴大量代码时,出现行错位等各种错乱,查找问题解决办法: vim进入文件后,先ESC 在出入 :set paste 回车后再按下 i 之后进行粘 ...
- python并发编程之协程(实践篇)
一.协程介绍 协程:是单线程下的并发,又称微线程,纤程.一句话说明什么是线程:协程是一种用户态的轻量级线程,即协程是由用户程序自己控制调度的. 对于单线程下,我们不可避免程序中出现io操作,但如果我们 ...
- WUSTOJ 1365: 矩阵旋转(Java)
题目链接:
- const关键字的使用——C语言
一.常规用法 关键字const用来定义只读变量,被const定义的变量它的值是不允许改变的,即不允许给它重新赋值,即使是赋相同的值也不可以.所以说它定义的是只读变量,这也就意味着必须在定义的时候就给它 ...
- 创客课堂——Scratch实例演示
大家好,这里是蓝精灵创客公益课堂,我是蓝老师. 前两期我们认识了Scratch的界面和菜单功能,本期我们就可以根据提示的步骤,学习一些Scratch的基本操作. 下面就开始今天学习内容 一.开始移动 ...