Вопрос

Окружающая среда: OS X 10,8, Go 1.0.2

Я делаю канал с размером буфера 2, тогда, если я напишу канал три раза, он бросит ошибку:

Брось: Все горутины спят - тупик!

Конечно, это правильно.

НО Если я напишу канал четыре или более раз в Goroutines, он работает нормально, почему? Емкость канала составляет 2, почему goroutines игнорируют это или забывают настройку емкости? Я комментирую коды чтения каналов, поэтому никто не будет читать канал и сохранить емкость. Я также использую время. Спи, чтобы ждать, пока все goroutines завершит свою работу.

Пожалуйста, просмотрите следующие коды: Main пакета

//import "fmt"

func main() {
    c := make(chan int, 2)
    /*c <- 1
    c <- 2
    c <- 3*/
    for i:=0; i<4; i++ {
        go func(i int) {
            c <- i
            c <- 9
            c <- 9
            c <- 9
        }(i)
    }
    time.Sleep(2000 * time.Millisecond)

    /*for i:=0; i<4*2; i++ {
        fmt.Println(<-c)
    }*/
}

Кто -нибудь, пожалуйста, даст несколько хитов? Спасибо, парни.

Это было полезно?

Решение

Когда канал буферирован, это означает, что он не будет блокировать, пока буфер не будет заполнен. После того, как буфер будет заполнен, отправляющая goroutine будет блокироваться, когда он пытается добавить вещи в канал.

Это означает, что это заблокирует:

c := make(chan int)
c <- 1          // Block here, this is unbuffered !
println(<-c)

И это будет также блокировать:

c := make(chan int, 2)
c <- 1
c <- 2
c <- 3           // Block here, buffer is full !
println(<-c)

Но точка Goroutines и Channel именно для того, чтобы запустить вещи одновременно, так что это сработает:

c := make(chan int)
go func() { c <- 1; }() // This will block in the spawned goroutine until...
println(<-c)            // ... this line is reached in the main goroutine

И аналогично:

c := make(chan int, 2)
go func() {  // `go ...` spawns a goroutine
    c <- 1   // Buffer is not full, no block
    c <- 2   // Buffer is not full, no block
    c <- 3   // Buffer is full, spawned goroutine is blocking until...
}()
println(<-c) // ... this line is reached in the main goroutine

В вашем примере вы порождаете четыре разных Goroutines, которые пишут четыре числа в один и тот же буферный канал. Поскольку буфер составляет 2 <16, они в конечном итоге блокируют

Но суть дела в том, что политика GO в Подождите, только основной Goroutine:

Выполнение программы начинается с инициализации основного пакета, а затем вызывая основную функцию. Когда основная функция возвращается, программа выходит. Это не ждет, пока другие (не-мэйн) goroutines завершится.

Это означает, что в вашем первом примере главный goroutine блокировался, когда он достиг линии c <- 3. Анкет Поскольку ни один другой goroutine не смог сделать что -либо, что могло бы его сблокировать, то время выполнения обнаружило, что программа была запущена и сообщила об ошибке.

Однако во втором примере, однако, порождено Goroutines блокируется, в то время как основной продолжается тихо, пока не достигнет конца своего исполнения, после чего все (заблокированные) породились горутины, молча убит, и не сообщается об ошибках.

Другие советы

дольдо дал хороший ответ. Я хотел бы добавить дополнительный совет, который я нашел полезным.

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

Рассуждение о сети без буферизации проще, хотя поначалу это может быть не очевидно.

Буферизация действительно полезна, но следует рассматривать как средство повышения производительности.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top