Обработка исключений GPars forkOffChild

Я использую fork/join GPars. Когда я выбрасываю исключение после вызова forkOffChild, оно скрывается.

Например:

def myRecursiveClosure = { boolean top ->
    try {
        if (!top) {
            throw new RuntimeException('child had a problem')
        } else {
            forkOffChild(false)
        }
    } catch (Exception exc) {
        println 'Exception handled internally'
        throw exc
    }
}

try {
     GParsPool.withPool {
         GParsPool.runForkJoin(true, myRecursiveClosure)
    }
} catch (Exception exc) {
     println 'Exception handled externally'
     throw exc
}

Здесь я устанавливаю флаг, чтобы знать, что замыкание было вызвано рекурсивно. Затем я выбрасываю исключение, которое перехватывается «внутри», но повторное выбрасывание никогда не перехватывается «извне». Поэтому я не знаю, что раздвоенный ребенок потерпел неудачу.

Я также пробовал обработчик исключений, но, похоже, он тоже не вызывается.

Это ожидаемое поведение или я делаю что-то не так? Есть ли какие-то стратегии, которые помогут в этом? Я не могу допустить, чтобы ребенок молча потерпел неудачу.

Спасибо!


person user1373467    schedule 15.11.2012    source источник


Ответы (1)


Важным моментом здесь является то, что forkOffChild() не ждет запуска дочернего элемента. Он просто планирует его выполнение. Таким образом, вы не можете ожидать, что метод forkOffChild() будет распространять исключения от дочернего объекта, поскольку они, вероятно, произойдут спустя много времени после того, как родительский объект возвратится из метода forkOffChild().

Однако обычно родителя интересуют результаты дочерних вычислений, поэтому в какой-то момент после разветвления он собирает результаты с помощью метода getChildrenResults(). Это возвращает вам список рассчитанных значений или повторно выдает потенциальные исключения.

Этот фрагмент показывает минимальное изменение для получения ожидаемого поведения:

   try {
        if (!top) {
            throw new RuntimeException('child had a problem')
        } else {
            forkOffChild(false)
            println childrenResults
        }
    } catch (Exception exc) {
        println 'Exception handled internally'
        throw exc
    }
person Vaclav Pech    schedule 16.11.2012
comment
Спасибо! Я и посмотрел на ваши примеры, Вацлав, и увидел это. - person user1373467; 16.11.2012
comment
Тьфу получил тайм-аут там. Ваше объяснение имеет смысл. Я попробовал, и это сработало. Я предполагаю, что это правильный подход и для асинхронных функций. После тестирования я вижу, что параллельные коллекции действительно передают его вызывающему абоненту, я предполагаю, что они делают что-то вроде «получения результата» внутри себя. Кажется, они в конечном итоге умирают, я думаю, нет хорошего способа мгновенно убить все потоки, если один из них получит исключение? - person user1373467; 16.11.2012
comment
Ну, здесь есть связанная проблема... whenBound не генерирует исключение, как это делает get(), и код закрытия не вызывается. Как вы обрабатываете исключения с помощью асинхронных функций и whenBound? Если хотите, я задам отдельный вопрос. Спасибо! - person user1373467; 16.11.2012
comment
Да, параллельные коллекции не отменяют текущие вычисления, если возникает исключение. - person Vaclav Pech; 17.11.2012
comment
Асинхронная функция привяжет исключение к возвращенному обещанию, поэтому get() повторно выдаст его, а whenBound() передаст его обработчику: result.whenBound{if (it instanceOf Exception) ... } - person Vaclav Pech; 17.11.2012
comment
Что ж, спасибо, я попробовал это, но, похоже, он никогда не попадет внутрь, когда Bound. Я использую версию 0.12, нужна ли мне более новая версия? - person user1373467; 18.11.2012
comment
Думаю, 0,12 должно быть достаточно. Выводит ли следующий код исключение? withPool { {-›throw new RuntimeException('test')}.asyncFun().call().whenBound {println it} } - person Vaclav Pech; 18.11.2012
comment
Вы уверены, что исключение распространяется за пределы вашей функции? - person Vaclav Pech; 18.11.2012
comment
Ваш код там, по сути, то, что я пробовал. Внутри асинхронной функции я намеренно выдал исключение. Если я делаю promise*.get() для результатов, исключение обнаруживается в основном потоке и выбрасывается обратно. Если я поставлю println или точки останова внутри whenBound, они никогда не произойдут. Я заметил, что изначально получил исключение времени выполнения, потому что я ввел свой аргумент закрытия whenBound в логическое значение, поэтому я подумал, что это будет работать, как вы предложили выше, и удалил тип, а не использовал «это». Но, как уже упоминалось, кажется, что он никогда не попадает внутрь закрытия whenBound. - person user1373467; 19.11.2012
comment
Я проверил, что старые версии GPars также корректно передают исключение в обработчик whenBound(). ATM Я понятия не имею, почему ваш обработчик не вызывается. - person Vaclav Pech; 19.11.2012