Можно ли получить результат от одного из ряда goroutines в Go? - PullRequest
3 голосов
/ 15 ноября 2009

Я только недавно узнал о языке программирования Google, Go. Я был заинтригован его предложенной поддержкой параллелизма, и намеревался узнать больше об этом. Однако я посмотрел, как в Go реализована особая функция параллелизма, и до сих пор я не видел никаких доказательств того, что эта функция вообще есть.

Вот гипотетическая ситуация: предположим, что мы программируем функцию для определения значения Foo конкретного входа. Для любого заданного входного значения значение Foo находится либо в домене A, либо в домене B (не в обоих). Методы поиска в этих доменах весьма различны, но они обладают тем свойством, что успешные поиски имеют тенденцию быстро возвращаться, в то время как неудачные поиски должны проходить через весь набор данных, чтобы быть исчерпывающими и поэтому занимают много времени.

Теперь в других языках, использующих параллелизм (например, Cilk ), можно запрограммировать функцию Foosearch так, чтобы она порождала функцию Asearch и функцию Bsearch. Эти функции будут выполняться одновременно, и всякий раз, когда любой из них придет с ответом, этот ответ будет сообщен вызывающей функции Foosearch, которая прекратит выполнение тех функций, которые он породил и которые не вернули.

Однако с помощью подпрограмм Go вы можете соединить только две подпрограммы с каналом - поэтому вы не можете настроить канал, на который может посылать Asearch или Bsearch, в зависимости от того, кто первым нашел ответ, и иметь Фузиарх читал из него. Кроме того, похоже, что вы не можете читать с канала, не блокируя его, поэтому вы не можете заставить Foosearch запускать Asearch и Bsearch и настраивать каналы с обоих, а затем запускать в цикле, проверяя, произвел ли тот или иной канал. ответ.

Правильно ли мое понимание границ параллелизма Го? Есть ли другой способ достижения данного результата?

Ответы [ 2 ]

16 голосов
/ 15 ноября 2009

Нет, я не верю, что вы правильно понимаете пределы Го.

Во-первых, в Go я не видел ничего такого, что ограничивало бы каналы для связи между двумя подпрограммами. Вы можете передать один и тот же канал как Asearch, так и Bsearch, а затем, в зависимости от того, что закончится, можно отправить результат по этому каналу.

Если вместо этого вы хотите использовать два канала и подождать, пока один из них получит результат, вы можете просто использовать оператор select. Из учебника Go , пример выбора канала, используемого для отправки запросов, и того, который сигнализирует серверу о выходе:

21    func server(op binOp, service chan *request, quit chan bool) {
22        for {
23            select {
24            case req := <-service:
25                go run(op, req);  // don't wait for it
26            case <-quit:
27                return;
28            }
29        }
30    }

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

Если выражение получения используется в назначение или инициализация форма

x, ok = <-ch
x, ok := <-ch
var x, ok = <-ch

операция получения становится неблокирующая. Если операция может продолжить, логическая переменная ок будет быть установленным в true и значение сохранено в Икс; в противном случае ОК устанавливается на ложь и х устанавливается в нулевое значение для его типа (§ Нулевое значение ).

Итак, есть несколько способов дождаться результата от нескольких процедур без блокировки. Я думаю, что я бы пошел с несколькими каналами, мультиплексированными с использованием select, так как таким образом вы можете легко определить, какая подпрограмма вернула результат, без необходимости упаковывать эту информацию в значение, которое вы отправляете, или делать какую-то другую форму вне полосная связь.

5 голосов
/ 15 ноября 2009

Вы можете использовать ключевое слово select для получения из нескольких каналов.

Значение будет взято из канала, который имеет результат раньше, чем остальные.

var c1, c2 chan int;
var result int;

select {
case result = <-c1:
    print("received ", result, " from c1\n");
case result = <-c2:
    print("received ", result, " from c2\n");
}

Ссылка

...