当前位置:首页 > 科技  > 软件

常见的 Goroutine 泄露,你应该避免

来源: 责编: 时间:2023-10-29 21:44:59 374观看
导读Go 语言编写代码的最大优点之一是能够在轻量级线程,即 Goroutines 中并发运行你的代码。然而,拥有强大的能力也伴随着巨大的责任。尽管 Goroutines 非常方便,但如果不小心处理,它们很容易引入难以追踪的错误。Goroutine

Go 语言编写代码的最大优点之一是能够在轻量级线程,即 Goroutines 中并发运行你的代码。nNp28资讯网——每日最新资讯28at.com

然而,拥有强大的能力也伴随着巨大的责任。nNp28资讯网——每日最新资讯28at.com

尽管 Goroutines 非常方便,但如果不小心处理,它们很容易引入难以追踪的错误。nNp28资讯网——每日最新资讯28at.com

Goroutine 泄露就是其中之一。它在背景中悄悄增长,可能最终在你不知情的情况下使你的应用程序崩溃。nNp28资讯网——每日最新资讯28at.com

因此,本文主要介绍 Goroutine 泄露是什么,以及你如何防止泄露发生。nNp28资讯网——每日最新资讯28at.com

我们来看看吧!nNp28资讯网——每日最新资讯28at.com

nNp28资讯网——每日最新资讯28at.com

什么是 Goroutine 泄露?

当创建一个新的 Goroutine 时,计算机在堆中分配内存,并在执行完成后释放它们。nNp28资讯网——每日最新资讯28at.com

Goroutine 泄露是一种内存泄露,当 Goroutine 没有终止并在应用程序的生命周期中被留在后台时就会发生。nNp28资讯网——每日最新资讯28at.com

让我们来看一个简单的例子。nNp28资讯网——每日最新资讯28at.com

func goroutineLeak(ch chan int) {    data := <- ch    fmt.Println(data)}func handler() {    ch := make(chan int)        go goroutineLeak(ch)    return}

随着处理器的返回,Goroutine 继续在后台活动,阻塞并等待数据通过通道发送 —— 这永远不会发生。nNp28资讯网——每日最新资讯28at.com

因此,产生了一个 Goroutine 泄露。nNp28资讯网——每日最新资讯28at.com

在本文中,我将引导你了解两种常见的模式,这些模式很容易导致 Goroutine 泄漏:nNp28资讯网——每日最新资讯28at.com

  • 遗忘的发送者
  • 被遗弃的接收者

让我们深入研究!nNp28资讯网——每日最新资讯28at.com

遗忘的发送者

遗忘的发送者发生在发送者被阻塞,因为没有接收者在通道的另一侧等待接收数据的情况。nNp28资讯网——每日最新资讯28at.com

func forgottenSender(ch chan int) {    data := 3      // This is blocked as no one is receiving the data    ch <- data}func handler () {    ch := make(chan int)      go forgottenSender(ch)    return}

虽然它起初看起来很简单,但在以下两种情境中很容易被忽视。nNp28资讯网——每日最新资讯28at.com

不当使用 Context

func forgottenSender(ch chan int) {    data := networkCall()      ch <- data}func handler() error {    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Millisecond)    defer cancel()      ch := make(chan int)    go forgottenSender(ch)      select {        case data := <- ch: {            fmt.Printf("Received data! %s", data)                  return nil        }            case <- ctx.Done(): {            return errors.New("Timeout! Process cancelled. Returning")        }    }}

在上面的例子中,我们模拟了一个标准的网络服务处理程序。nNp28资讯网——每日最新资讯28at.com

我们定义了一个上下文,它在10ms后发出超时,随后是一个异步进行网络调用的Goroutine。nNp28资讯网——每日最新资讯28at.com

select语句等待多个通道操作。它会阻塞,直到其其中一个情况可以运行并执行该情况。nNp28资讯网——每日最新资讯28at.com

如果网络调用完成之前超时到达,case <- ctx.Done() 将会执行,处理程序将返回一个错误。nNp28资讯网——每日最新资讯28at.com

当处理程序返回时,不再有任何接收者等待接收数据。forgottenSender将被阻塞,等待有人接收数据,但这永远不会发生!nNp28资讯网——每日最新资讯28at.com

这就是Goroutine泄露的地方。nNp28资讯网——每日最新资讯28at.com

错误检查后的接收者位置

这是另一个典型的情况。nNp28资讯网——每日最新资讯28at.com

func forgottenSender(ch chan int) {    data := networkCall()      ch <- data}func handler() error {    ch := make(chan int)    go forgottenSender(ch)      err := continueToValidateOtherData()    if err != nil {        return errors.New("Data is invalid! Returning.")    }      data := <- ch      return nil}

在上面的例子中,我们定义了一个处理程序并生成一个新的Goroutine来异步进行网络调用。nNp28资讯网——每日最新资讯28at.com

在等待调用返回的过程中,我们继续其他的验证逻辑。nNp28资讯网——每日最新资讯28at.com

如你所见,当continueToValidateOtherData返回一个错误导致处理程序返回时,泄露就发生了。nNp28资讯网——每日最新资讯28at.com

没有人等待接收数据,forgottenSender将永远被阻塞!nNp28资讯网——每日最新资讯28at.com

解决方案:忘记的发送者

使用一个缓冲通道。nNp28资讯网——每日最新资讯28at.com

如果你回想一下,忘记的发送者发生是因为另一端没有接收者。阻塞问题的罪魁祸首是一个无缓冲的通道!nNp28资讯网——每日最新资讯28at.com

一个无缓冲的通道是在消息发出时立即需要一个接收者的,否则发送者会被阻塞。它是在没有为通道分配容量的情况下声明的。nNp28资讯网——每日最新资讯28at.com

func forgottenSender(ch chan int) {    data := 3      // This will NOT block    ch <- data}func handler() {    // Declare a BUFFERED channel    ch := make(chan int, 1)      go forgottenSender(ch)    return}

通过为通道添加特定的容量,在这种情况下为1,我们可以减少所有提到的问题。nNp28资讯网——每日最新资讯28at.com

发送者可以在不需要接收者的情况下将数据注入通道。nNp28资讯网——每日最新资讯28at.com

被遗弃的接收者

正如其名字所暗示的,被遗弃的接收者是完全相反的情况。nNp28资讯网——每日最新资讯28at.com

当一个接收者被阻塞,因为另一边没有发送者发送数据时,它就会发生。nNp28资讯网——每日最新资讯28at.com

func abandonedReceiver(ch chan int) {    // This will be blocked    data := <- ch      fmt.Println(data) }func handler() {    ch := make(chan int)      go abandonedReceiver(ch)      return}

第3行一直被阻塞,因为没有发送者发送数据。nNp28资讯网——每日最新资讯28at.com

让我们再次了解两个常见的场景,这些场景经常被忽视。nNp28资讯网——每日最新资讯28at.com

发送者未关闭的通道

func abandonedWorker(ch chan string) {    for data := range ch {        processData(data)    }      fmt.Println("Worker is done, shutting down")}func handler(inputData []string) {    ch := make(chan string, len(inputData))      for _, data := range inputData {        ch <- data    }      go abandonedWorker(ch)        return}

在上面的例子中,处理程序接收一个字符串切片,创建一个通道并将数据插入到通道中。nNp28资讯网——每日最新资讯28at.com

处理程序然后通过Goroutine启动一个工作程序。工作程序预计会处理数据,并且一旦处理完通道中的所有数据,就会终止。nNp28资讯网——每日最新资讯28at.com

然而,即使消耗并处理了所有的数据,工作程序也永远不会到达“第6行”!nNp28资讯网——每日最新资讯28at.com

尽管通道是空的,但它没有被关闭!工作程序继续认为未来可能会有传入的数据。因此,它坐下来并永远等待。nNp28资讯网——每日最新资讯28at.com

这是Goroutine再次泄漏的地方。nNp28资讯网——每日最新资讯28at.com

在错误检查之后放置发送者

这与我们之前的一些示例非常相似。nNp28资讯网——每日最新资讯28at.com

func abandonedWorker(ch chan []int) {    data := <- ch    fmt.Println(data)}func handler() error {    ch := make(chan []int)    go abandonedWorker(ch)    records, err := getFromDB()    if err != nil {        return errors.New("Database error. Returning")    }    ch <- records    return nil}

在上面的例子中,处理程序首先启动一个Goroutine工作程序来处理和消费一些数据。nNp28资讯网——每日最新资讯28at.com

然后,处理程序从数据库中查询记录,然后将记录注入通道供工作程序使用。nNp28资讯网——每日最新资讯28at.com

如果数据库出现错误,处理程序将立即返回。通道将不再有任何发送者传入数据。nNp28资讯网——每日最新资讯28at.com

因此,工作程序被遗弃。nNp28资讯网——每日最新资讯28at.com

解决方案:被遗弃的接收者

在这两种情况下,接收者都被留下,因为他们“认为”通道将有传入的数据。因此,它们阻塞并永远等待。nNp28资讯网——每日最新资讯28at.com

解决方案是一个简单的单行代码。nNp28资讯网——每日最新资讯28at.com

defer close(ch)

当你启动一个新的通道时,最好的做法是推迟关闭通道。nNp28资讯网——每日最新资讯28at.com

这确保在数据发送完成或函数退出时关闭通道。nNp28资讯网——每日最新资讯28at.com

接收者可以判断一个通道是否已关闭,并相应地终止。nNp28资讯网——每日最新资讯28at.com

func abandonedReceiver(ch chan int) {    // This will NOT be blocked FOREVER    data := <- ch      fmt.Println(data) }func handler() {    ch := make(chan int)        // Defer the CLOSING of channel    defer close(ch)      go abandonedReceiver(ch)    return}

结论

关于 Goroutine 泄漏就是这么多了!nNp28资讯网——每日最新资讯28at.com

尽管它不像其他 Goroutine 错误那么强大,但这种泄漏仍然会大大耗尽应用程序的内存使用。nNp28资讯网——每日最新资讯28at.com

记住,拥有强大的力量也伴随着巨大的责任。nNp28资讯网——每日最新资讯28at.com

保护我们的应用程序免受错误的责任在于你我——开发人员!nNp28资讯网——每日最新资讯28at.com

本文链接:http://www.28at.com/showinfo-26-15597-0.html常见的 Goroutine 泄露,你应该避免

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: 并发编程:你真的能回答好AQS吗(补充中断机制)

下一篇: Python自动查重:原理、方法与实践

标签:
  • 热门焦点
  • 0糖0卡0脂 旭日森林仙草乌龙茶优惠:15瓶到手29元

    旭日森林无糖仙草乌龙茶510ml*15瓶平时要卖为79.9元,今日下单领取50元优惠券,到手价为29.9元。产品规格:0糖0卡0脂,添加草本仙草汁,清凉爽口,富含茶多酚,保留
  • 把LangChain跑起来的三个方法

    使用LangChain开发LLM应用时,需要机器进行GLM部署,好多同学第一步就被劝退了,那么如何绕过这个步骤先学习LLM模型的应用,对Langchain进行快速上手?本片讲解3个把LangChain跑起来
  • 服务存储设计模式:Cache-Aside模式

    Cache-Aside模式一种常用的缓存方式,通常是把数据从主存储加载到KV缓存中,加速后续的访问。在存在重复度的场景,Cache-Aside可以提升服务性能,降低底层存储的压力,缺点是缓存和底
  • 微软邀请 Microsoft 365 商业用户,测试视频编辑器 Clipchamp

    8 月 1 日消息,微软近日宣布即将面向 Microsoft 365 商业用户,开放 Clipchamp 应用,邀请用户通过该应用来编辑视频。微软于 2021 年收购 Clipchamp,随后开始逐步整合到 Microsof
  • 重估百度丨“晚熟”的百度云,能等到春天吗?

    &copy;自象限原创作者|程心排版|王喻可2016年7月13日,百度云计算战略发布会在北京举行,宣告着百度智能云的正式启程。彼时的会场座无虚席,甚至排队排到了门外,在场的所有人几乎都
  • 年轻人的“职场羞耻感”,无处不在

    作者:冯晓亭 陶 淘 李 欣 张 琳 马舒叶来源:燃次元&ldquo;人在职场,应该选择什么样的着装?&rdquo;近日,在网络上,一个与着装相关的帖子引发关注,在该帖子里,一位在高级写字楼亚洲金
  • 东方甄选单飞:有些鸟注定是关不住的

    作者:彭宽鸿来源:华尔街科技眼&zwj;&zwj;&zwj;&zwj;&zwj;&zwj;&zwj;&zwj;&zwj;&zwj;东方甄选创始人俞敏洪带队的&ldquo;7天甘肃行&rdquo;直播活动已在近日顺利收官。成立后一
  • 重估百度丨大模型,能撑起百度的“今天”吗?

    自象限原创 作者|程心 罗辑2023年之前,对于自己的&ldquo;今天&rdquo;,百度也很迷茫。&ldquo;新业务到 2022 年底还是 0,希望 2023 年出来一个 1。&rdquo;这是2022年底,李彦宏
  • iQOO Neo8 Pro即将开售:到手价3099元起 安卓性能最强旗舰

    5月23日,iQOO如期举行了新品发布会,全新的iQOO Neo8系列也正式与大家见面,包含iQOO Neo8和iQOO Neo8 Pro两个版本,其中标准版搭载高通骁龙8+,而Pro版更
Top