Golang Многоканальный порядок записи / получения - PullRequest
0 голосов
/ 08 мая 2018

Моя конкретная проблема заключается в том, что у меня есть небуферизованный канал, и я порождаю несколько процедур, ограниченных семафором для выполнения работы:

func main() {
    sem := make(chan struct{}, 10) // allow ten concurrent parsers
    wg := &sync.WaitGroup{}
    wg.Add(1)
    DoSomething("http://example.com", sem, wg)

    wg.Wait()
    // all done
}

func DoSomething(u string, sem chan struct{}, wg *sync.WaitGroup) {
    defer wg.Done()

    sem <- struct{}{}        // grab
    defer func() { <-sem }() // release


    var newSomethings []string

    // ...

    for u := range newSomethings {
        wg.Add(1)
        go DoSomething(u)
    }
}

Если в стеке несколько DoSomething подпрограмм, заблокированных при записи sem (или обратно при чтении). Когда происходит запись, есть ли порядок, которому подпрограмма go справляется с записью? Я предполагаю, что это было случайно, но я мог вообразить:

  • это случайно
  • запись / получение происходят в том порядке, в котором они зарегистрированы
  • зависит от реализации

Я посмотрел пару ресурсов и не смог найти решение:

Мне интересно, если это не определено и / или зависит от реализации, или эта логика находится и определена где-то в ядре go?

1 Ответ

0 голосов
/ 08 мая 2018

Порядок обслуживания блоков, заблокированных в операции отправки, не определен, но реализован как FIFO.Вы можете увидеть реализацию в runtime / chan.go , которая использует связанный список для отслеживания отправителей и получателей канала.

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

func main() {
    ch := make(chan int)
    ready := make(chan int)

    for i := 0; i < 10; i++ {
        i := i
        go func() {
            ready <- 1
            ch <- i
        }()
        <-ready
        runtime.Gosched()
    }

    for i := 0; i < 10; i++ {
        v := <-ch
        if i != v {
            panic("out of order!")
        }
        fmt.Println(v)
    }
}

https://play.golang.org/p/u0ukR-5Ptw4

Это технически некорректно, потому что нет способа наблюдать блокировку операции отправки, поэтому между отправкой ready все еще есть гонкаи отправьте на ch на следующей строке.Мы можем попытаться устранить это с помощью вызова runtime.Gosched здесь или даже time.Sleep, но без явной синхронизации нет гарантии, что «произойдет до» отношения .

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...