人皆犯错,宽恕是德 — Alexander Pope

这些都是我在写 Go 中犯的错误。尽管这些可能不会导致任何类型的错误,但它们可能会潜在地影响软件。

  内循环  

有几种方法可以造成循环内部的混乱,你需要注意。

1.1 使用引用循环迭代变量

由于效率的原因,循环迭代变量是单个变量,在每次循环迭代中采用不同的值。这可能会导致不知情的行为。

结果将是:

正如你所看到的,out 切片中的所有元素都是 3。实际上,实际上很容易解释为什么会发生这种情况:在每次迭代中,我们都会将 v 的地址附加到 out 切片中。如前所述,v 是在每次迭代中接受新值的单个变量。因此,正如您在输出的第二行中看到的,地址是相同的,并且所有地址都指向相同的值。

简单的解决方法是将循环迭代器变量复制到新变量中:

新的输出:

同样的问题可以找到正在 Goroutine 中使用的循环迭代变量。

结果将是:

它可以使用上面提到的相同的解决方案来修复。注意,如果不使用 Goroutine 运行该函数,代码将按照预期运行。

1.2 在循环中调用 WaitGroup.Wait

使用 WaitGroup 类型的共享变量会犯此错误,如下面的代码所示,当第 5 行的 Done()被调用 len(tasks) 次数时,第 7 行的 Wait() 只能被解除阻塞,因为它被用作参数在第 2 行调用 Add()。但是,Wait() 在循环中被调用,因此在下一个迭代中,它会阻止在第 4 行创建 Goroutine。简单的解决方案是将 Wait() 的调用移出循环。

1.3 在循环中使用 defer

defer 直到函数返回才执行。除非你确定你在做什么,否则你不应该在循环中使用 defer

在上面的例子中,如果你使用第 8 行而不是第 10 行,下一次迭代就不能持有互斥锁,因为锁已经在使用中,并且循环永远阻塞。

如果你真的需要使用 defer 内循环,你可能想委托另一个函数来做这项工作。

但是,有时使用 defer 在循环可能会变得很方便。所以你真的需要知道你在做什么。

Go 不能容忍愚蠢者

  发送到一个无保证的 channel  

您可以将值从一个 Goroutine 发送到 channels,并将这些值接收到另一个 Goroutine。默认情况下,发送和接收,直到另一方准备好。这允许 Goroutines 在没有显式锁或条件变量的情况下进行同步。

让我们检查一下上面的代码。doReq 函数在第 4 行创建一个子 Goroutine 来处理请求,这在Go服务程序中是一种常见的做法。子 Goroutine 执行 do 函数并通过第 6 行通道 ch 将结果发送回父节点。子进程会在第 6 行阻塞,直到父进程在第 9 行接收到 ch 的结果。同时,父进程将阻塞 select,直到子进程将结果发送给 ch(第9行)或发生超时(第11行)。如果超时发生在更早的时候,父函数将从第 12 行 doReq 方法返回,并且没有人可以再接收 ch 的结果,这将导致子函数永远被阻塞。解决方案是将 ch 从无缓冲通道更改为缓冲通道,这样即使父及退出,子 Goroutine 也始终可以发送结果。另一个修复方法是在第 6 行使用默认为空的 select 语句,这样如果没有 Goroutine 接收 ch,就会发生默认情况。尽管这种解决方案可能并不总是有效。

  不使用接口  

接口可以使代码更加灵活。这是在代码中引入多态的一种方法。接口允许您请求一组行为,而不是特定类型。不使用接口可能不会导致任何错误,但它会导致代码不简单、不灵活和不具有可扩展性。

在众多接口中,io.Reader 和 io.Writer 可能是最受欢迎的。

这些接口可以非常强大。假设您要将对象写入文件中,因此您定义了一个 Save 方法:

如果您第二天需要写入 http.ResponseWriter 该怎么办?您不想定义新方法。是吧?所以使用 io.Writer

还有一个重要的注意事项,你应该知道,总是要求你要使用的行为。在上面的例子中,请求一个io.ReadWriteCloser 也可以工作得很好,但当你要使用的唯一方法是 Write时,这不是一个最佳实践。接口越大,抽象就越弱。

所以大多数时候你最好专注于行为而不是具体的类型。

  不好的顺序结构  

这个错误也不会导致任何错误,但是它会导致更多的内存使用。

似乎两种类型的大小都相同,为 21 个字节,但结果显示出完全不同。使用 GOARCH=amd64 编译代码,BadOrderedPerson 类型分配 32 字节,而 OrderedPerson类型分配 24 字节。为什么?原因是数据结构对齐。在 64 位体系结构中,内存分配 8 字节的连续数据包。需要添加的填充可以通过以下方式计算:

当您有一个大的常用类型时,它可能会导致性能问题。但是不要担心,您不必手动处理所有的结构。使用 maligned 你可以轻松检查代码以解决此问题。

  在测试中没有使用 race detector  

数据竞争会导致神秘的故障,通常是在代码部署到生产环境很久之后。正因为如此,它们是并发系统中最常见也是最难调试的 bug 类型。为了帮助区分这些 bug, Go 1.1 引入了一个内置的数据竞争检测器。它可以简单地添加 -race 标志。

启用 race 检测器后,编译器将记录在代码中访问内存的时间和方式,而 runtime 监视对共享变量的不同步访问。

当发现数据竞争时,竞争检测器将打印一份报告,其中包含冲突访问的堆栈跟踪。下面是一个例子:

  最后一句  

唯一真正的错误是我们什么也没学到。

译自:https://medium.com/swlh/5-mistakes-ive-made-in-go-75fb64b943b8

go 向buff写入一个字节_我在 Go 中犯的 5 个错误相关推荐

  1. python一个中文占几个字节_中文在python中占几个字节

    如果是utf-8编码,那么一个中文字符占用三个字节,一个英文字符占用一个字节.如果是gbk编码,那么一个中文字符占用两个字节,一个英文字符占用一个字节. 如果是utf-8编码,那么一个中文包含繁体字等 ...

  2. java定义常量语法错误的是_在Java接口中定义常量,下面语法错误的是( )_学小易找答案...

    [单选题]Why did Ben's emotions change so much? [判断题]Write the title in the middle of the first line. [单 ...

  3. 485通信少发一个字节_一文搞懂Modbus与RS485通信协议

    在工业控制.电力通讯.智能仪表等领域,通常情况下是采用串口通信的方式进行数据交换.最初采用的方式是RS232接口,由于工业现场比较复杂,各种电气设备会在环境中产生比较多的电磁干扰,会导致信号传输错误. ...

  4. python定义一个列表_如何在Python中创建用户定义的列表?

    你需要将怪物的数量发送给使用它的函数:def welcome(): number = monsters() print('Alright, ' + str(number) + ' monsters.' ...

  5. python随机选取列表中的一个字符串_如何从Python中的列表中选择随机字符串?

    因此,首先您可能需要检查pythons list()函数对字符串做了什么. python doc 简单的put list("foo")将创建列表['f','o','o'].我猜这可 ...

  6. java 复制一个数组_浅谈Java中复制数组的方式

    在Java里面,可以用复制语句"A=B"给基本类型的数据传递值,但是如果A,B是两个同类型的数组,复制就相当于将一个数组变量的引用传递给另一个数组:如果一个数组发生改变,那么引用同 ...

  7. java当前月份减一个月_在java编程中怎样用%表示当前月份的上一个月和下一个月...

    我可以结合自己的经验大致给你说一说,希望对你有所帮助,少走些弯路. 学习Java其实应该上升到如何学习程序设计这种境界,其实学习程序设计又是接受一种编程思想.每一种语言的程序设计思想大同小异,只是一些 ...

  8. python制作一个计时器_如何在python中创建一个反应计时器作为GUI?

    我有一个反应计时器的问题.我想在我的程序中有一个按钮,它能告诉我从定时器开始按下按钮所花的时间.在 假设我打开我的程序,我想要一个按钮,如果我点击它,它将打印出计时器启动后我按下它所花的时间.然后在我 ...

  9. python数组删除最后一个元素_删除numpy数组中的最后一个元素

    我有一个纽比阵列:array([ 0.49010508, 0. , 0. , 0. , 0. , 0. , 0. , 0. , 0.09438115, 0. , 0. , 0. , 0. , 0. , ...

最新文章

  1. python easygui_EasyGUI是python的一个超级简单的GUI工具介绍(一)
  2. linux 禁止SU 登录
  3. AI服务器的优势有哪些?人工智能服务器产品有哪些?
  4. 正直、智慧、成熟、诚信——毒霸用人的基本原则
  5. 酷客多基金在济南大学成立“酷客多奖助学金“
  6. 对C#面向对象三大特性的一点总结
  7. 后端技术:消息队列MQ/JMS/Kafka相关知识介绍
  8. 删除logs mysql_关于删除MySQL Logs的一点记录
  9. php面向对象教学笔记,php学习笔记之面向对象编程
  10. 在WinForm中使用Web Service来实现软件自动升级
  11. C# struct 性能损失
  12. 字体的基础知识:中文字体的特征
  13. python-numpy常用知识汇总
  14. Windows 2016 出現 0xc0000135 ServerManager.exe 无法启用
  15. 【最优估计学习笔记】概率密度函数
  16. Cocos Creator 国旗头像生成器,源码奉上!
  17. html怎么设置p元素居中,CSS 如何使p层水平居中
  18. 如何防止服务器记录上网信息,服务器怎么监控上网记录
  19. 拼团返利模式玩法VS最新拼团的商业模式
  20. 超强 Python 数据可视化库,一文全解析

热门文章

  1. 反其道而行:教人写烂代码的开源项目
  2. 【DD推荐】还用翻译工具给参数和方法取名?装个插件快速搞定!
  3. mysql 线上加索引_mysql手札,唯一索引引发的线上事故
  4. oracle显性游标,Oracle高级显式游标的使用
  5. 采用全文索引解决模糊查询速度慢的问题
  6. MultiResUNet笔记
  7. opencv 连通域笔记
  8. python opencv 透视变换
  9. pytorch 图像与tensor转换
  10. python 图像降噪