你好!本文是“ Golang并发编程”系列的第三篇文章?
在上一篇文章中,我们了解了渠道的基本用法。不熟悉的朋友可以先阅读上一篇文章。
当使用频道在Goroutine之间进行通信时,有时场景会变得非常复杂,因此偶尔难以检测并且无法定位的虫子(例如服务和OOM)。
在本文中,我们可以清理通道中常用的三个常见坑:恐慌,死锁和内存泄漏,以防止问题发生之前。
汇编时,GO语言新手很容易遇到此僵局的问题:
这是我喜欢看到的“死锁” ...在操作系统中,我们了解到“死锁”是两个彼此等待的线程,它们被消耗了,并且过程必须结束。Dead Lock“ Go语言也相似。两个goroutine互相等待,导致该程序在那里消费并无法继续运行。在阅读很多死亡锁时,可以将渠道引起的死锁汇总为以下类型的案例(未封闭的渠道的情况第一的):
渠道的生产商和消费者必须成对出现。如果缺少一个人,它将导致死锁,例如:
或者:
除了需要出现之外,它还需要出现在不同的goroutine中,例如::::
用于缓冲频道:
缓冲通道将把接收到的元素放在首位,然后将发生阻塞。发生阻塞时,如果主要goroutine被阻止,将会出现僵局
因此,在实际使用中,建议尽可能多地使用缓冲通道。
通常在发布过程中的警报或观察记忆中发现内存泄漏。服务记忆通常会缓慢上升,直到系统OOM在空中丢失为止。
在GO语言中,错误使用通道可能会导致Goroutine泄漏,从而导致内存泄漏。
无法修复错误,我不会写错误?goroutine泄漏的核心是:
生产者/消费者所在的Goroutine已退出,相应的消费者/生产者的Goroutine将始终阻止它,直到流程退出流程
我们通常使用频道执行一些超时控件,例如,以下示例:
在这里,我们使用Goroutine模拟IO操作,以及模拟客户端处理逻辑的主要Goroutine。
如果这是在服务器代码中,则处理此请求后,它将被悬挂和泄漏,只需等待OOM =。=。
如果生产者不继续生产,则消费者所在的Goroutine也将阻止并且不会退出:例如:
在这种情况下,您只需要增加操作即可。收到关闭信号后,将退出操作。Goroutine将不再被阻止,可以回收。
防止Goroutine泄漏的核心是:
创建Goroutine时,您必须弄清楚何时回收
特定于执行级别,包括:
恐慌更加令人兴奋。通常,在测试期间找不到。偶尔在发布后,该程序被挂起,并且在服务发生后触发警报。渠道引起的恐慌通常是以下原因:
让我们首先给一个简单的栗子:
在实际开发过程中,在处理多个Goroutine合作时,可能会有一个具有频道的Goroutine。另一个不知道。如果您进入结束,例如,您将删除:
所有弊端的来源是在Go语言中。您不知道是否闭合了频道,因此在尝试进行近距离操作时,您应该准备好慌张...
与上述相同,在尝试在频道中发送数据时,您应该考虑
当我第一次遇到上面提到的恐慌问题时,我还试图找到一个内置的功能来检查闭合状态。结果,我发现没有这样的功能...
因此,如果有这样的功能,它真的可以解决恐慌问题吗?答案不是。因为频道是在并发环境中的收发器操作,即使当前结果是错误的,它仍然无法直接进行。例如,以下代码:以下代码:
遵循较少的原则是更多,此功能还不够
结论:除非您必须关闭Chan。
当Chan没有发件人和接收器时,它不再使用,GC会在一段时间后标记和清理此陈通知机制,尤其是当生产者和消费者之间的关系为1:m时,通过近距离告诉下游:我已经完成工作,不要读它。
Chan的原则关闭了:
只要我们遵循这两个原则,我们就可以避免两个恐慌场景,即:将数据发送到封闭的陈或关闭封闭的陈。
根据生产者与消费者之间的关系,可以将其分解为以下类别:
这种情况来自参考材料中的“如何优雅关闭渠道”。GO 101系列非常好。推荐阅读?
待续 ...
原始:https://juejin.cn/post/7100597828359028750