doucai1901 2017-07-10 19:52
浏览 32
已采纳

范围内的通道完成死锁

The following code ends with a fatal error: all goroutines are asleep - deadlock!

// Package letter returns the frequency of letters in texts using parallel computation.
package letter

import "fmt"

const testVersion = 1

type FreqMap map[rune]int

func Frequency(s string) FreqMap {
    m := FreqMap{}
    for _, r := range s {
        m[r]++
    }
    return m
}

func ConcurrentFrequency(l []string) FreqMap {
    ch := make(chan FreqMap)
    for _, s := range l {
        go func() {
            ch <- Frequency(s)
        }()
    }
    m := FreqMap{}
    for c := range ch {
        fmt.Println("channel:", c)
        for k, v := range c {
            m[k] += v
        }
    }
    return m
}

This is output:

channel: map[121:8 101:42 98:8 104:28 102:6 71:1 59:1 97:33 110:15 103:15 112:6 109:5 116:38 10:7 87:2 107:1 108:17 99:3 117:7 39:5 79:4 114:27 105:15 44:7 119:8 100:12 63:2 65:1 118:3 45:1 32:72 111:18 115:24]
channel: map[97:33 110:15 111:18 117:7 108:17 45:1 115:24 10:7 79:4 32:72 121:8 100:12 105:15 63:2 107:1 71:1 119:8 114:27 103:15 102:6 65:1 44:7 87:2 118:3 101:42 98:8 116:38 39:5 112:6 104:28 109:5 99:3 59:1]
channel: map[99:3 116:38 104:28 108:17 44:7 117:7 119:8 114:27 10:7 87:2 110:15 100:12 103:15 107:1 32:72 111:18 102:6 59:1 45:1 101:42 109:5 63:2 115:24 97:33 105:15 112:6 65:1 71:1 79:4 121:8 98:8 39:5 118:3]
fatal error: all goroutines are asleep - deadlock!

My understanding is that range waits for data from channel until the channel is closed, but adding close(ch) inside the for loop, or inside the func() or after those, make things worse (the fmt.Println does not get anything) - tried also with defer (same problem)

What would be the correct approach? Isn't range the right solution in this case ?

Thanks a lot !

  • 写回答

2条回答 默认 最新

  • dtrj74376 2017-07-10 19:57
    关注

    Range only stops when the channel is closed. You're hitting a deadlock because nothing is writing to the channel, but you're sitting waiting for something to be written. You could add a sync.WaitGroup and close the channel after all of the goroutines writing to it have finished.

    You should probably also change the loop as there is potential for the wrong values to be passed because you're closing over the loop variable which can change concurrently; this will be more reliable:

    for _, s := range l {
        go func(s rune) {
            ch <- Frequency(s)
        }(s)
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 使用cuda加速opencv运算但是报错AttributeError: module 'cv2.cuda' has no attribute 'getCudaEnabledDeviceCount'
  • ¥15 java输入输出异常
  • ¥15 三子连珠对弈小游戏制作
  • ¥15 C++扑克牌游戏的编程
  • ¥15 有人能看一下我宿舍管理系统的报修功能该怎么改啊?链表那里总是越界
  • ¥15 cs loadimage运行不了,easyx也下了,没有用
  • ¥15 r包runway详细安装教程
  • ¥15 Html中读取Json文件中数据并制作表格
  • ¥15 谁有RH342练习环境
  • ¥15 STM32F407 DMA中断问题