Можно ли получить результат от одной из нескольких горутин в Go?

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

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

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

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

Правильно ли я понимаю ограничения параллелизма Go? Есть ли другой способ достичь данного результата?


person afeldspar    schedule 15.11.2009    source источник


Ответы (2)


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

Во-первых, я не видел в 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

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

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

person Brian Campbell    schedule 15.11.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");
}

Справочник

person Randy Sugianto 'Yuku'    schedule 15.11.2009