Внутренняя функция горутины

Я прочитал https://go.dev/blog/pipelines и там есть две функции:

// move numbers into a channel 
func gen(nums ...int) <-chan int {
    out := make(chan int)
    go func() {
        for _, n := range nums {
            out <- n
        }
        close(out)
    }()
    return out
}

// square those numbers take from "in" channel
func sq(in <-chan int) <-chan int {
    out := make(chan int)
    go func() {
        for n := range in {
            out <- n * n
        }
        close(out)
    }()
    return out
}

и внутри основной функции

    in := gen(2, 3)

    // Distribute the sq work across two goroutines that both read from in.
    c1 := sq(in)
    c2 := sq(in)

Я думал, что sq — это обычная функция, поэтому c1 должна принимать все значения из канала «in», а c2 пуста, но это не так.

То есть это означает, что горутина внутри функции все еще может выйти за пределы этой функции и вернуться в основную процедуру для выполнения следующей команды?

«Область функции» — это что-то из C. В go нет ничего, что является областью функции (за исключением, возможно, main, который является особенным, и фреймов стека, которые видны через пакет времени выполнения).

Paul Hankin 02.06.2024 11:34
Создание API ввода вопросов на разных языках программирования (Python, PHP, Go и Node.js)
Создание API ввода вопросов на разных языках программирования (Python, PHP, Go и Node.js)
API ввода вопросов - это полезный инструмент для интеграции моделей машинного обучения, таких как ChatGPT, в приложения, требующие обработки...
1
1
100
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Здесь вы неправильно понимаете концепцию горутин, возможно, вам захочется изучить Обзор Go: Concurrency.

Как объяснено «Функция gen запускает горутину, которая отправляет целые числа» и «Второй этап, sq», также запускает горутину, которая «получает целые числа» и «выдает квадрат каждого полученного целого числа». И gen, и sq создают (результат) канал, в который внутренне запланированные горутины отправляют целые числа и немедленно возвращают этот канал, не дожидаясь запуска горутин.

Таким образом, оба gen и sq возвращаются немедленно, в то время как горутины только запланированы к выполнению, но еще не выполнены. (Обратите внимание, что это наиболее вероятный порядок выполнения, здесь ничто не дает никаких гарантий синхронизации)

Вероятно, это не лучший материал для изучения Go, вам следует сначала написать синхронный код. См. также «очередь производитель-потребитель» в «Переосмысление классических шаблонов параллелизма».

Предположим, мы заблокируем перед вызовом merge: поскольку все каналы небуферизованы («отправляет и получает блокировку до тех пор, пока другая сторона не будет готова») после запуска примера «Разветвление, разветвление» горутина, запущенная gen в конечном итоге попадает в расписание, отправляет два значения, а затем блокируется при попытке отправить третье значение, в то время как горутины, запущенные sq, планируются, получают по одному значению каждый и теперь блокируются при попытке отправить квадрат в соответствующий выходной канал.

Пока что это не имеет ничего общего с «областью действия». Единственное, что захватывается областью горутины, — это переменная канала.

Когда вы выполняете этот пример на машине с достаточным количеством ядер ЦП, все горутины выполняются параллельно. Обратите внимание: когда вы звоните merge и достаточно быстро читаете исходящие каналы, порядок может измениться.

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