2ord
@2ord
продвинутый чайник

Почему получается deadlock? Что-то не так с получателем?

Разбираюсь с работой Go каналов. Написал тестовую программу, суть которой в последовательной обработке данных, получаемых в одном канале из другого.
Получаю ошибку
fatal error: all goroutines are asleep - deadlock!

код
package main

import (
	"fmt"
	"time"
)

var numChan chan int
var labelChan <-chan string

func main() {
	input := []int{3, 1, 8, 7, 5, 9, 2}
	numChan = make(chan int)

	go func() {
		labelsReceiver(labelChan)
	}()
	time.Sleep(time.Millisecond) // Так попытался убедиться, что получатель стартует первым. Не знаю как правильно сделать.

	go func() {
		labelChan = labelsEmitter(numChan)
	}()

	for _, num := range input {
		fmt.Println(num)
		numChan <- num
	}
}

func labelsEmitter(numbers chan int) <-chan string {
	fmt.Println("go labelsEmitter")
	out := make(chan string, 3)
	defer close(out)
	for num := range numbers {
		time.Sleep(time.Millisecond * 200)
		str := fmt.Sprintf("Number %d", num)
		out <- str
	}
	return out
}

func labelsReceiver(labelChanRcv <-chan string) {
	fmt.Println("go labelsReceiver")
	for label := range labelChanRcv {
		fmt.Println(label)
	}
}

Но если увеличить размер буферизованного канала в сткроке
out := make(chan string, 3)
, скажем, до 10, то программа хоть и не выводит label, но и не валится с ошибкой выше.
  • Вопрос задан
  • 121 просмотр
Решения вопроса 1
Попробуйте так:
package main

import (
	"fmt"
	"time"
)

var numChan chan int
var outChan chan string

func main() {
	input := []int{3, 1, 8, 7, 5, 9, 2}
	numChan = make(chan int)
	outChan = make(chan string)
	go func() {
		labelsReceiver(outChan)
	}()
	time.Sleep(time.Millisecond) // Так попытался убедиться, что получатель стартует первым. Не знаю как правильно сделать.

	go func() {
		labelsEmitter(numChan, outChan)
	}()

	for _, num := range input {
		fmt.Println(num)
		numChan <- num
	}
	close(numChan)
	close(outChan)
}

func labelsEmitter(numbers chan int, outChan chan string) {
	fmt.Println("go labelsEmitter")
	//out := make(chan string, 3)
	//defer close(out)
	for num := range numbers {
		time.Sleep(time.Millisecond * 200)
		str := fmt.Sprintf("Number %d", num)
		outChan <- str
	}
	return
}

func labelsReceiver(labelChanRcv <-chan string) {
	fmt.Println("go labelsReceiver")
	for label := range labelChanRcv {
		fmt.Println("label", label)
	}
}
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
passionkillah
@passionkillah
Backend-разработчик
Могу ошибаться, но по-моему, дело в том, что вы переопределяете labelChan. Сначала вы в labelsReceiver передаете переменную, которая была объявлена над main() (она передается по значению - то есть в labelsReceiver вы взаимодействуете с копией переменной labelChan), а затем вы из метода labelsEmitter возвращаете другой канал, в который вы пишете, но из которого не читаете. А при увеличении буфера до 10 ошибки нет потому, что чисел в input'е меньше 10-ти => они просто записываются в буфер, но их все еще никто не читает.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы
OnederX Москва
от 100 000 до 120 000 ₽
Эвотор Москва
от 180 000 до 300 000 ₽
Level Travel Москва
от 130 000 до 200 000 ₽
11 авг. 2020, в 16:48
15000 руб./за проект
11 авг. 2020, в 16:48
1000 руб./за проект