Ответ
Попытка параллельной записи в небуферизированный канал приведет к deadlock (взаимной блокировке).
Объяснение:
Небуферизированный канал (make(chan T)
) требует, чтобы и отправитель, и получатель были готовы к обмену данными одновременно (это называется рандеву). Операция записи в такой канал блокирует горутину-отправителя до тех пор, пока другая горутина не будет готова прочитать из этого канала.
Если несколько горутин попытаются одновременно записать данные в один и тот же небуферизированный канал, только одна из них сможет завершить операцию (и то, только если есть готовый читатель). Все остальные горутины-писатели заблокируются. Если количество читателей меньше количества писателей, заблокированные горутины никогда не смогут продолжить выполнение, что и вызовет deadlock
.
Пример:
package main
import (
"fmt"
"time"
)
func main() {
ch := make(chan int) // Небуферизированный канал
go func() {
fmt.Println("Горутина 1: пытается отправить 1")
ch <- 1 // Блокируется здесь
fmt.Println("Горутина 1: отправила 1")
}()
go func() {
fmt.Println("Горутина 2: пытается отправить 2")
ch <- 2 // И эта горутина тоже блокируется
fmt.Println("Горутина 2: отправила 2")
}()
// Так как нет читателей, обе горутины заблокируются навсегда.
// Среда выполнения Go обнаружит это и завершит программу с ошибкой:
// fatal error: all goroutines are asleep - deadlock!
time.Sleep(time.Second)
}
Решения:
- Использовать буферизированный канал (
make(chan int, N)
), если вы хотите разрешить отправкуN
значений без немедленной блокировки. - Организовать пул воркеров, где чтение и запись синхронизированы, например, с помощью
sync.WaitGroup
. - Использовать
select
сdefault
для неблокирующей отправки.