go语言的一些陷阱

作者: lazypos | 来源:发表于2017-11-09 12:20 被阅读206次

            虽然go语言使用起来方便简单,但他有很多特性是比较与众不同的,在不了解的情况下,编码时候就会产生很多莫名其妙的bug。

    channel

    channel示例代码

            这里的channel默认是无缓冲的,但是有三个线程往里面写,而函数返回的时候只从中读取了一个,根据channel的特性,另外两个线程(go routine 个人别称 线程)中,另外两个线程会一直阻塞在ch <- true 这一行,造成资源泄漏(内存涨)。

    解决办法

            有两个解决办法,第一种使用select加上default的办法,这样,当channel无法写入的时候,就会触发default退出。

    换成select和default

            另一个办法是创建channel的时候,容量足够大,大于等于3,使得写入不阻塞。

    创建管道指定容量大小

    go routine

    示例代码

            以为会输出1,2,3 实际却输出了3,3,3,原因是V这个变量是同一个地址重复使用,三次循环 &V 的地址都是一样的,只是V的值改变了,而GetId()函数的调用是用指针是调用的,所以船体给go routine的是V的地址,三次都一样。然而go routine是异步开启的,循环执行太快导致三个go routine得到的该地址值是最后一个了

    解决办法

            如果在gov.GetId() 之后加上足够时间的sleep()让该 routine 建立起来,则可以避免这样的问题。

    加上sleep确保线程开启

            或者先用一个临时变量存储v的值,再用临时变量开启routine

    使用临时变量

    range

    示例代码

            原本以为在 循环刚开始的时候,把arr[1]的值改成10后,第二次循环的时候v会输出 10,结果arr[1]的值确实是改了,而 v 依旧输出是20。

            原因是如果是数组等非指针类型,会在循环前复制一份,循环的时候使用的是复制的值。(channel/map/slice/指针数组等不会这样)

    解决办法

            尽量使用指针数组或者切片(slice)。

    创建的时候是切片 循环的时候转成切片

    slice

    示例代码

            同样是去掉第二个元素,用函数的方式却跟预料的不一样。

            原因:实际上,切片作为参数的时候,虽然内容是指针,切片本身是拷贝,就是说函数内外 &arr 的地址不一样,但 &arr[n] 里面的元素的地址是一样的, 所以函数外的arr长度并没有减少。

    解决办法

            使用返回值重新赋值的方式。

    返回切片

    相关文章

      网友评论

      • 卡卡西D:第一个channel 是无缓冲的,并不是容量为1,容量为1 的叫有缓冲的channel,概念上不同,效果也不同的
        lazypos::smirk: 多谢指正

      本文标题:go语言的一些陷阱

      本文链接:https://www.haomeiwen.com/subject/drjpmxtx.html