去死锁所有 goroutines 睡着了

这是我之前帖子的后续:


    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-1rM3aXC

linkgetter 和 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}

            }

    }

    

通道关闭的方式有什么问题?


慕侠2389804
浏览 114回答 1
1回答

qq_笑_17

在这里,您并没有真正关注您的管道设计。你必须问自己“X 部分什么时候完成?完成后会发生什么?完成后会发生什么?”&nbsp;对于管道的每个部分。您启动head,tail以及worker以射程超过通道。这些函数成功返回的唯一方法是关闭这些通道。把它画出来你需要。head(in)&nbsp;馈入&nbsp;inworker(out, in, &wg)覆盖in,输入out,并告诉您它已完成,wg一旦in关闭tail(out)&nbsp;范围超过&nbsp;out那么你需要做什么:确保处理所有输入?确保所有 goroutine 都返回?像这样:您需要关闭in从head一旦处理完所有的文件。这将导致在处理worker它可以从中获取的所有项目后实际返回in,导致wg.Wait()返回现在可以安全关闭,out因为没有任何东西进入它,这将导致tail最终返回。但是您可能需要另一个sync.WaitGroup与tail此特定设计相关的程序,因为整个程序将在wg.Wait()返回时立即退出,因此可能无法完成tail正在执行的所有工作。见这里。具体来说:程序执行首先初始化主包,然后调用函数 main。当该函数调用返回时,程序退出。它不会等待其他(非主)goroutine 完成。您可能还想使用此处引用的缓冲通道来帮助避免在 goroutine 之间进行过多的切换执行。对于您当前的设计,您在上下文切换上浪费了大量时间。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go