Почему этот буферный канал не блокируется в моем коде? - PullRequest
0 голосов
/ 30 января 2020

Я учу язык Go. Может кто-нибудь объяснить, пожалуйста, здесь вывод?

package main

import "fmt"

var c = make(chan int, 1)

func f() {

    c <- 1

    fmt.Println("In f()")
}

func main() {
    go f()

    c <- 2
    fmt.Println(<-c)
    fmt.Println(<-c)

}

Вывод:

In f()
2
1

Process finished with exit code 0

Почему «In f ()» встречалось до «2»? Если «In f ()» напечатано до «2», буферизованный канал должен блокироваться. Но этого не произошло, почему?

Остальные результаты разумны.

Изображение моего запутанного результата

Ответы [ 2 ]

2 голосов
/ 30 января 2020

Порядок событий, которые вызывают это, таков:

  1. Запуск программы.
  2. Запись 2 в канал. Емкость канала исчерпана.
  3. Чтение из канала и вывод результата.
  4. Запись 1 в канал.
  5. Чтение из канала и вывод результата.

Порядок событий, приводящих к этой тупиковой ситуации, таков:

  1. Запуск процедуры.
  2. Запись 1 в канал. Емкость канала исчерпана.
  3. Запись 2 в канал. Поскольку буфер канала заполнен, он блокируется.

Вывод, который вы предоставляете, кажется, указывает, что программа завершается первой, а программа не блокируется, что противоречит двум сценариям ios в качестве объяснения. Вот что происходит:

  1. Запуск программы.
  2. Запись 2 в канал.
  3. Чтение 2 из канала.
  4. Записать 1 в канал.
  5. Вывод In f().
  6. Вывести 2, полученный от канала.
  7. Считывание 1 из канала.
  8. Выведите 1, полученное от канала.

Имейте в виду, что у вас нет никаких гарантий относительно планирования программ, если вы не выполняете их программным образом. Когда вы запускаете программу, она не определена, когда фактически выполняется первый код этой программы и насколько прогрессирует исходный код до тех пор. Обратите внимание, что поскольку ваш код основан на определенном порядке событий, он нарушается этим определением, просто чтобы сказать это явно.

Кроме того, в любой точке вашей программы планировщик может принять решение о переключении между различными программами , Даже одна строка fmt.Printtln(<-c) состоит из нескольких шагов, и между каждым шагом может происходить переключение.

1 голос
/ 30 января 2020

Чтобы воспроизвести блок, вам нужно многократно запустить этот код, чтобы сделать это с помощью test. У вас нет блочной причины удачи. Но это не гарантируется:

var c = make(chan int, 1)

func f() {

    c <- 1

    fmt.Println("In f()")
}

func TestF(t *testing.T) {
    go f()

    c <- 2
    fmt.Println(<-c)
    fmt.Println(<-c)

}

и запускается с командой:

go test -race -count=1000 -run=TestF -timeout=4s

, где count количество тестов. Это воспроизводит блокировку для меня. Укажите время ожидания, чтобы не ждать по умолчанию 10 минут

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...