Порядок вывода канала Голанг - PullRequest
0 голосов
/ 02 июня 2018
func main() {
  messages := make(chan string)
  go func() { messages <- "hello" }()
  go func() { messages <- "ping" }()
  msg := <-messages
  msg2 := <-messages
  fmt.Println(msg)
  fmt.Println(msg2)

Приведенный выше код последовательно печатает «ping» и затем «hello» на моем терминале.Я запутался в том порядке, в котором это печатается, поэтому мне было интересно, смогу ли я получить некоторые разъяснения по поводу моего мышления.

Я понимаю, что небуферизованные каналы блокируются при ожидании как отправителя, так и получателя.Таким образом, в приведенном выше случае, когда выполняются эти 2 подпрограммы, в обоих случаях еще нет получателя.Поэтому я предполагаю, что обе процедуры блокируются до тех пор, пока на канале не появится приемник.

Теперь ... Я бы предположил, что сначала в канал пробуется "привет", но он должен ждать ... вВ это же время «пинг» пытается, но снова приходится ждать.Затем появляется

msg := <- messages

, поэтому я предполагаю, что на этом этапе программа произвольно выберет одну из ожидающих программ и разрешит ей отправить свое сообщение в канал, поскольку msg готова к приему.

Однако, кажется, что независимо от того, сколько раз я запускаю программу, всегда сообщается, что msg назначается «ping», а msg2 назначается «hello», что создает впечатление, что «ping» всегдаполучает приоритет для отправки первым (в MSG).Почему это?

Ответы [ 3 ]

0 голосов
/ 02 июня 2018

В Golang Spec Порядок каналов описывается следующим образом: -

Каналы действуют как очереди «первым пришел - первым вышел».Например, если одна программа отправляет значения по каналу, а вторая программа получает их, значения принимаются в отправленном порядке.

Она печатает, какое значение доступно первым для получения на другом конце,Если вы хотите синхронизировать их, используйте разные каналы или добавьте wait Groups.

package main

import (
    "fmt"
)

func main() {
  messages1 := make(chan string)
  messages2 := make(chan string)
  go func(<-chan string) {
        messages2 <- "ping" 
    }(messages2)
  go func(<-chan string) {
        messages1 <- "hello" 
    }(messages1)
  fmt.Println(<-messages1)
  fmt.Println(<-messages2)
}

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

игровая площадка Go

0 голосов
/ 25 августа 2018

Я только что прошел через то же самое.Смотрите мой пост здесь: Каналы Голанга, порядок исполнения

Как и вы, я видел шаблон, который был нелогичным.В месте, где на самом деле не должно быть шаблона.Как только вы запустили процесс go, вы запустили поток выполнения, и в этот момент все ставки отключены в том порядке, в котором потоки будут выполнять свои шаги.Но если должен был быть порядок, логика сообщает нам, что первый вызванный будет выполнен первым.

На самом деле, если вы перекомпилируете эту программу каждый раз, результаты будут отличаться.Это то, что я нашел, когда начал компилировать / запускать его на своем локальном компьютере.Чтобы сделать результаты случайными, мне пришлось «испачкать» файл, например, добавив и удалив пробел.Затем компилятор перекомпилирует программу, и тогда я получу случайный порядок выполнения.Но при компиляции в песочнице go результат всегда был одинаковым.

При использовании песочницы результаты, по-видимому, кэшируются.Я не смог получить заказ на изменение в песочнице с помощью незначительных изменений.Единственный способ изменить его - это ввести команду time.Sleep (1) между запуском операторов go.Тогда первый запущенный будет первым выполненным каждый раз.Я до сих пор не думаю, что ставлю свою жизнь на то, чтобы это продолжалось, хотя, потому что они являются отдельными потоками исполнения, и нет никаких гарантий.не должно быть никакого детерминизма.Это то, что застряло у меня.Я был полностью прояснен, когда обнаружил, что результаты действительно случайны в нормальной среде.Песочница - это отличный инструмент.Но это не нормальная среда.Скомпилируйте и запустите ваш код локально, и вы увидите ожидаемые результаты.

0 голосов
/ 02 июня 2018

Речь идет не о порядке чтения канала, а о порядке выполнения подпрограмм, который не гарантируется.

Попробуйте «Println» из функции, в которой вы пишете в канал (до и после записи), иЯ думаю, что это должно быть в том же порядке, что и чтение с канала.

...