Программа с оператором select выходит из тупика в go - PullRequest
0 голосов
/ 02 апреля 2020

На этот вопрос вполне возможно, что я не смог найти его, поэтому здесь у нас go:

У меня есть эта go функция, которая отправляет или получает "сообщения", в зависимости от того, какая из них доступна, используя оператор select:

func Seek(name string, match chan string) {
select {
case peer := <-match:
    fmt.Printf("%s sent a message to %s.\n", peer, name)
case match <- name:
    // Wait for someone to receive my message.

Я запускаю эту функцию на 4 различных go -программах, используя небуферизованный канал (было бы лучше использовать буфер och 1, но это просто эксперимент):

people := []string{"Anna", "Bob", "Cody", "Dave"}
match := make(chan string)
for _, name := range people {
    go Seek(name, match, wg)

Теперь я только начал использовать go и подумал, что, поскольку мы используем небуферизованный канал, операторы отправки и получения в "select" должны блокироваться (никто не ждет отправить сообщение, чтобы вы не могли его получить, и никто не ждет, чтобы вы могли его получить, и вы не можете его отправить), что означает, что не будет никакой связи между функциями, или Deadlock. Однако выполнение кода показывает нам, что это не так:

API server listening at: 127.0.0.1:48731
Dave sent a message to Cody.
Anna sent a message to Bob.
Process exiting with code: 0

Мой вопрос к вам, милые люди, почему это происходит? Понимает ли компилятор, что функции хотят читать / писать в одном и том же канале, и организует это? Или оператор "select" постоянно проверяет, есть ли кто-нибудь, кто может использовать канал?

Извините, если на этот вопрос сложно ответить, я все еще новичок и не настолько опытен в том, как работают сцена:)

1 Ответ

1 голос
/ 02 апреля 2020

Теперь я только начал использовать go и подумал, что, поскольку мы используем небуферизованный канал, операторы отправки и получения из оператора "select" должны блокироваться (никто не ожидает отправки сообщение, чтобы вы не могли его получить, и никто не ждет, чтобы вы могли его получить, поэтому вы не можете отправить)

Это на самом деле не так; на самом деле, есть несколько процедур, ожидающих получения, и несколько процедур, ожидающих отправки. Когда goroutine делает select как у вас:

select {
case peer := <-match:
    fmt.Printf("%s sent a message to %s.\n", peer, name)
case match <- name:
    // Wait for someone to receive my message.

Он одновременно ожидает отправки и получения. Поскольку у вас есть несколько подпрограмм, каждая подпрограмма найдет как отправителей, так и получателей. Ничто не заблокирует. selects выберет case с случайным образом, так как несколько случаев разблокируются одновременно.

...