Запуск прогонов до действительного результата от одного из них - PullRequest
0 голосов
/ 31 октября 2019

Есть ли способ запустить некоторые процедуры, пока одна из них не вернет допустимое значение (целое число больше нуля)? внутри goroutine я должен угадать число, которое мне нужно поместить в математическую формулу

1 Ответ

2 голосов
/ 31 октября 2019

Вы должны написать это сами.

Программа запускается, пока не вернется. Каждая программа сама решает, когда возвращаться.

Предположим, у вас есть функции / процедуры A, B и C, каждая из которых выполняет длинные вычисления, и один из трех может найти полезный ответ первым, а два другихдолжен остановиться, если так. В этом случае вы захотите выделить три программы, которые выполняют вычисления:

func doA(args) {
    ... do computing for A ...
    ... deliver a result ...
    return  // this line is redundant, and here only for illustration
}

func doB(args) {
    ... do computing for B ...
    ... deliver a result ...
}

и т. Д.

Что входит в args? Ну, это зависит от вас, но это хорошая идея дать всем трем функциям какой-то способ узнать, что одна из других дала полезный ответ, и они должны остановиться. Довольно умный способ сделать это состоит в том, чтобы иметь канал, который кто-то - кто бы ни решил, что результат «полезен», например - закрывает , чтобы указать, что все остальные должны прекратить работать. Все функции do могут выглядеть следующим образом:

func doA(done chan struct{}, other_args) {
    var result_ready bool

    for !result_ready {
        select {
        case <-done: // someone else delivered a good result
            return   // so stop working now
        default:
            ... work a bit more ...
        }
    }
    ... deliver result ...
}

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

Здесь есть несколько хитростей, которые следует рассмотреть. Предположим, что драйвер main хочет просмотреть несколько результатов и выбрать «достаточно хороший» по некоторым показателям, которые мы не хотим кодировать в каждом работнике. Каждый работник должен сделать некоторую работу и отправить пока ответ, а затем продолжать работать , пока main не скажет "Мне нравится один из полученных ответов", main закрыв канал done,Затем мы получаем структуру кода, подобную этой:

func doA(done chan struct{}, resultChan chan resulttype, args) {
    for {
        select {
        case <-done:
            return
        default:
             ... do a little work ...
             ... try to deliver result-so-far ...
        }
    }
}

Попытка получить результат до сих пор должна выглядеть так:

select {
case <-done:
    return
case resultChan <- result:
}

Thisвполне может устранить необходимость в более раннем select: у нас есть вещь, которая вычисляет A вычисление, пока не будет готов результат, затем обрабатывают либо «вы можете выйти сейчас», либо «ваш результатотправлено ", в зависимости от того, что произойдет первым. Если сначала вы можете выйти, вы можете выйти. Если «ваш результат отправляется», он сразу же приступает к решению проблемы next .

В худшем случае doA работает немного дольше, чем нужно: сколько бы он ни длилсятребуется, чтобы получить один результат.

Обратите внимание, что концепция "готового канала", наряду с множеством других лесов, полезных во многих реальных программах, содержится в идее context . См. Шаблоны Go Concurrency: контекст и, более прямо относящиеся к вашей проблеме, Шаблоны Go Concurrency: конвейеры и аннулирование .

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