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

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

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

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

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

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

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

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

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


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

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

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

    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. Я не сильный гошник, могу в чём-то ошибаться.

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

    ОтветитьУдалить
  4. Ну на самом деле именно такие "простые" и используются.
    Но вот напримеры реальных проектов:
    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 можно увидеть при чтении, не при записи.

    ОтветитьУдалить
  5. @Pavel Vainerman:

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

    ОтветитьУдалить