Карта не работает, закрываю ли я канал или нет - PullRequest
0 голосов
/ 05 апреля 2019

Это домашнее задание и вопрос для начинающих.Я отредактировал вопрос, так как допустил обнаруженную ошибку.

Я пытаюсь сделать параллельные карты частот из текста и получаю сообщение об ошибке в последней операции (уменьшение карт)

Кажется, код работает до этого момента.

Если я закрываю канал, я получаю ошибку: "panic: send on closed channel"

Если я не закрываю канал, я получаю: "fatalошибка: все программы спят - тупик! "

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 голосов
/ 05 апреля 2019

1. Первый вопрос: паника

Если я закрываю канал, я получаю сообщение об ошибке: "panic: send on closed channel"

Почему? Один из вас пытается запрограммировать запись на канал, который вы уже закрыли в вызывающей (основной) программе. В вашем случае в функции WordCount.

В текущей версии вашего кода panic не воспроизводится с моим тестовым предложением, но вы можете легко вызвать это, например. если бы вы позвонили 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 о том, что программа составляет Done до того, как произойдет фактическая запись в канал. Вызывающая программа (функция WordCount) в какой-то момент считает, что все гурутины выполнены (строка wg.Wait()) и закрывает канал. Но одна из ваших подпрограмм, которая еще не закончила писать, попытается написать на закрытый канал. Тогда вы получите panic.

Как исправить:

Использование defer в processToCounting функция

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

Что читать:

Смотрите для начинающих в Тур по Го / Параллелизм

Отправка по закрытому каналу вызовет панику.

и документация для: close

Отправка или закрытие закрытого канала вызывает панику во время выполнения.

2. Второй вопрос: тупик

Если я не закрываю канал, я получаю: «фатальная ошибка: все программы спят - тупик!»

У вас есть цикл for, который читает канал. Эта петля for заблокирована навсегда. В ожидании новых значений из канала, но никто больше не напишет туда.

См. Тур по Го / Параллелизм

Цикл для диапазона i: = c многократно принимает значения от канала до его закрытия.

и см. Документацию по Каналам

Приемники всегда блокируются, пока нет данных для приема

0 голосов
/ 05 апреля 2019

Q1: почему close(wordChannel) вызывает панику

A:

  1. вы положили wg.Done() перед отправкой результата в канал
  2. канал не является буферным каналом, что означает, что он будет зависать при записи до тех пор, пока не будет выполнено чтение. но чтение происходит после закрытия канала. последовательность закрытия канала -> чтение канала -> запись канала -> паника

Q2: почему тупик.

A: fmt.Print(<-wordChannel) прочитать сообщение из канала, чтобы последний цикл не мог прочитать сообщение numberOfGroups. оно ждет последнего сообщения навсегда.

for i := 0; i < numberOfGroups; i++ {
        for k, v := range <- wordChannel {
            finalMap[k] += v
        }
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...