вторник, 17 декабря 2019 г.

[prog.golang] Нужны наглядные примеры применения select для записи в Go-шные каналы

Обращаюсь за помощью к людям, которые знают Go (применяют в работе или просто интересуются): мне нужны примеры использования конструкции select для неблокирующей записи сообщений в канал. Примеры из жизни. Особенно такие, где select использовалась бы для записи сразу в несколько каналов. Поделитесь плиз. Особенно хорошо будет если кто-нибудь сможет дать ссылку на github/gitlab/bitbucket/... репозиторий, в котором эти примеры можно будет увидеть вживую.

Нужно мне этого для того, чтобы попытаться представить, как подобную вещь можно реализовать в C++ (в SObjectizer-е понятное дело). Но т.к. сам я к Go отношения не имею, то у меня гуглятся только какие-то учебные примеры, вроде чисел Фибоначчи :(

5 комментариев:

Pavel Vainerman комментирует...

Ну если по простому то вот так

Допустим out - это канал с блокирующей записью (без буфера или с уже переполненым буфером).
Т.е. запись в него по умолчанию заблокирует поток выполнения пока буфер не осободиться или кто-то не прочтёт.

Предположим нужно либо записать, либо через 5 секунд выдать timeout
То это можно записать так:

select {
case out <- msg:
case <-time.After(5*time.Second):
return
}


Другой пример. Записать в "блокирующий канал" (без ожидания)

select {
case out <- msg:
default:
fmt.Println("write failed..")
}

Pavel Vainerman комментирует...

Соответственно в одном селект в принципе можно и совместить чтение и запись

select {
case out <- msg:
case dat:= <- input:
fmt.Print("read %v\n", dat)
case <-time.After(5*time.Second):
return
}

При этом сработает что-то одно (что первее).

Насчёт записи сразу в несколько каналов. В одном селект вроде как это не делается.
Поэтому либо конструкцию (с timeout) вынести в фукнкцию и просто запускать её в горутине
go send(msg1)
go send(msg2)
go send(msg3)

либо просто последовательно написать select-ы для каждого канала (например с default, чтобы без ожидания), но они будут выполняться последовательно.

P.S. Я не сильный гошник, могу в чём-то ошибаться.

eao197 комментирует...

Такие простые примеры очевидны, но от них очень сильно пахнет "синтетикой", т.е. понятно что они показывают, но непонятно насколько это востребовано на практике. Хотелось бы примеров именно из реальных задач.

Pavel Vainerman комментирует...

Ну на самом деле именно такие "простые" и используются.
Но вот напримеры реальных проектов:
https://github.com/fsnotify/fsnotify/blob/4bf2d1fec78374803a39307bfb8d340688f4f28e/kqueue.go#L445
https://github.com/nats-io/nats.go/blob/5a67486c44f5f20ffacb7afdfc6aa2db7cb112c6/timer.go#L49
https://github.com/nats-io/nats.go/blob/5a67486c44f5f20ffacb7afdfc6aa2db7cb112c6/nats.go#L1337

Вот тут (правда это чтение)
https://github.com/moleculer-go/moleculer/blob/246ad3a3b9bce75bdc5b407ceb15b7596fc97890/broker/broker.go#L446


P.S. Чаще всего конечно разнообразие использования select можно увидеть при чтении, не при записи.

eao197 комментирует...

@Pavel Vainerman:

Спасибо за ссылки. Посмотрю.