为了账号安全,请及时绑定邮箱和手机立即绑定

去死锁所有 goroutines 睡着了

去死锁所有 goroutines 睡着了

Go
慕侠2389804 2021-12-07 10:13:22
这是我之前帖子的后续:    http://stackoverflow.com/questions/34736825/goroutine-exit-status-2-what-does-it-mean-why-is-it-happening?noredirect=1#comment57238789_34736825在阅读了 SO 内外的多个主题和文章后,我仍然无法确定应该关闭渠道的位置。该程序将打开一个文件列表,为每个输入文件创建一个输出文件(具有相同的名称),访问每个输入文件中的所有 url 并从中获取所有 href 链接 - 保存到相应的输出文件中。但是,我收到以下错误:    http://play.golang.org/p/8X-1rM3aXClinkgetter 和 getHref 函数主要用于处理。Head 和 tail 作为单独的 goroutine 运行,而 worker 进行处理。    package main    import (    "bufio"    "bytes"    "fmt"    "golang.org/x/net/html"    "io"    "io/ioutil"    "log"    "net/http"    "os"    "path/filepath"    "regexp"    "sync"    )    type Work struct {    Link     string    Filename string    }    type Output struct {    Href     string    Filename string    }    func getHref(t html.Token) (href string, ok bool) {    // Iterate over all of the Token's attributes until we find an    "href"    for _, a := range t.Attr {            if a.Key == "href" {                    href = a.Val                    ok = true            }    }    return    }    func linkGetter(out chan<- Output, r io.Reader, filename string) {    z := html.NewTokenizer(r)    for {            tt := z.Next()            switch {            case tt == html.ErrorToken:                    return            case tt == html.StartTagToken:                    t := z.Token()                    isAnchor := t.Data == "a"                    if !isAnchor {                            continue                    }                    // Extract the href value, if there is one                    url, ok := getHref(t)                    if !ok {                            continue                    }                    out <- Output{url, filename}            }    }    通道关闭的方式有什么问题?
查看完整描述

1 回答

?
qq_笑_17

TA贡献1818条经验 获得超7个赞

在这里,您并没有真正关注您的管道设计。你必须问自己“X 部分什么时候完成?完成后会发生什么?完成后会发生什么?” 对于管道的每个部分。

您启动headtail以及worker以射程超过通道。这些函数成功返回的唯一方法是关闭这些通道。

把它画出来你需要。

  1. head(in) 馈入 in

  2. worker(out, in, &wg)覆盖in,输入out,并告诉您它已完成,wg一旦in关闭

  3. tail(out) 范围超过 out

那么你需要做什么:

  1. 确保处理所有输入?

  2. 确保所有 goroutine 都返回?

像这样:

  1. 您需要关闭inhead一旦处理完所有的文件。

  2. 这将导致在处理worker它可以从中获取的所有项目后实际返回in,导致wg.Wait()返回

  3. 现在可以安全关闭,out因为没有任何东西进入它,这将导致tail最终返回。

但是您可能需要另一个sync.WaitGrouptail此特定设计相关的程序,因为整个程序将在wg.Wait()返回时立即退出,因此可能无法完成tail正在执行的所有工作。见这里。具体来说:

程序执行首先初始化主包,然后调用函数 main。当该函数调用返回时,程序退出。它不会等待其他(非主)goroutine 完成。

您可能还想使用此处引用的缓冲通道来帮助避免在 goroutine 之间进行过多的切换执行。对于您当前的设计,您在上下文切换上浪费了大量时间。


查看完整回答
反对 回复 2021-12-07
  • 1 回答
  • 0 关注
  • 113 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信