无论是否关闭频道,缩小地图都无法正常工作

时间:2019-04-05 04:41:55

标签: go indexing

这是作业和初学者的问题。因为我发现了一个错误,所以我编辑了问题。

我正在尝试从文本中创建并行频率图,但是在上一次操作中出现错误(缩小图)

代码似乎可以正常工作。

如果我关闭频道,则会出现错误: “恐慌:在封闭频道上发送”

如果我不关闭频道,则会得到: “致命错误:所有goroutine都在睡觉-死锁!”

func WordCount(text string) {

    text = strings.ToLower(text)
    re := regexp.MustCompile("\\w+")
    sentence := re.FindAllString(text, -1)

    numberOfGroups := 4
    piece := len(sentence) / numberOfGroups

    wordChannel := make(chan map[string]int)

    wg := new(sync.WaitGroup)
    wg.Add(numberOfGroups)

    for i := 0; i < numberOfGroups; i ++ {
        go processToCounting(sentence[i*piece:(i+1)*piece], wordChannel, wg)
    }

    wg.Wait()
    fmt.Print(<-wordChannel)
    fmt.Print("\n")

    finalMap := make(map[string]int)
    close(wordChannel)

    for i := 0; i < numberOfGroups; i++ {
        for k, v := range <- wordChannel {
            finalMap[k] += v
        }
    }
}

func processToCounting(textSlice []string, wordChannel chan map[string]int, wg *sync.WaitGroup) {
    freq := make(map[string]int)
    for _, v := range textSlice {
        freq[v]++
    }
    wg.Done()
    wordChannel <- freq
}

2 个答案:

答案 0 :(得分:0)

第一季度:为什么close(wordChannel)引发恐慌

A:

  1. 您将wg.Done()放在结果插入频道之前
  2. 该通道是一个非缓冲通道,这意味着它将一直停留在写入操作之前,直到读取为止。但读取是在您关闭频道后发生的。顺序是关闭通道->读取通道->写入通道->紧急情况

第二季度:为什么出现僵局。

A:fmt.Print(<-wordChannel)从通道中读取一条消息,因此最后一个循环无法读取numberOfGroups消息。它会永远等待最后一条消息。

for i := 0; i < numberOfGroups; i++ {
        for k, v := range <- wordChannel {
            finalMap[k] += v
        }
    }

答案 1 :(得分:0)

1。第一个问题:恐慌

  

如果我关闭频道,则会收到错误消息:“紧急:在关闭的频道上发送”

为什么?您的goroutine之一正在尝试写入已在调用(主)goroutine中关闭的通道。就您而言,使用WordCount函数。

在当前版本的代码中,panic is not reproducible和我的测试语句一起出现,但是您很容易造成这种情况,例如如果您会在close(wordChannel)之前致电wg.Wait()

让我们看看processToCounting中的错误,它可能会导致panic

wg.Done() // tells to the WaitGroup that the gouroutine is Done (decrements the counter of goroutines)
wordChannel <- freq // trying to write to the channel

在实际写入通道之前,wg.Done()WaitGroup发出信号,表明goroutine为Done。在某些时候调用goroutine(WordCount函数)认为所有gouroutine都已完成(wg.Wait()行)并关闭了通道。但是您的goroutine之一尚未完成写入,将尝试写入关闭的通道。然后您将得到panic

如何解决:

processToCounting函数中使用defer

defer wg.Done() // triggers wg.Done right before the function returns (but after writing to the channel in your case) 

阅读内容:

A Tour of Go / Concurrency中查找初学者

  

在封闭的频道上发送会引起恐慌。

和文档:close

  

发送到或关闭已关闭的频道会导致运行时恐慌。

2。第二个问题:死锁

  

如果我不关闭通道,则会得到:“致命错误:所有goroutine都在睡眠-死锁!”

您有一个用于从通道读取的for循环。此for循环将永远锁定。等待通道中的新值,但是没有人会再写在那里。

参见A Tour of Go / Concurrency

  

i:=范围c的循环反复从通道接收值,直到关闭为止。

并查看Channels

的文档
  

接收者总是阻塞,直到有数据要接收为止