NullPointerException в GPars, Актер

Groovy: 1,8,6

GPars: 0,12 или 1,2,1

ОС: Ubuntu 14.04 LTS

@Grab(group='org.codehaus.gpars', module='gpars', version='0.12')
import groovyx.gpars.actor.Actor


import groovyx.gpars.actor.Actors


def a = 1
def b = 100000

def reactor2 = Actors.reactor {
    println " $it"
}

def reactor1 = Actors.reactor {
    println "$it"
    reactor2 << it
}

Actor actor = Actors.actor {
    (a..b).each {reactor1 << it}
}

actor.join()

reactor1.stop()
reactor1.join()

reactor2.stop()
reactor2.join()

Когда этот код выполняется, NullPointerException встречается часто. Чем шире и шире диапазон значений a и b, тем легче и легче возникает эта ошибка. Но ошибка никогда не возникает, когда диапазон ограничен.

Я не могу понять, почему произошла ошибка.

1 ответ

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

Учитывая это, у вашего кода есть некоторые проблемы. Основной проблемой является отсутствие loop{} закрытие, которое страхует Actor ожидает следующего входящего сообщения после его обработки.

Во-вторых, ссылаясь stop() тоже не помогает Это просто останавливает Actor от получения дополнительных сообщений. В вашем случае это не повредит, так как вы немедленно вызываете join, но добавляет путаницы.

Чтобы это работало, вот ваш код, упрощенный до рабочего примера:

import groovyx.gpars.actor.Actors

def a = 1
def b = 100000

def actor = Actors.actor {
    loop {
       react {
            println it
        }
    }
}

(a..b).each {
    actor << it
}
actor.join()

В этом примере для каждого значения в диапазоне к субъекту добавляется сообщение, которое реагирует на сообщение, печатая значение, а затем, из-за закрытия цикла, ожидает следующего входящего сообщения.

Так что этот пример должен выполнить то, что вы хотите. Однако, чтобы дать некоторую ясность в том, что происходит в вашем коде, вот объяснение.

Когда ваш Actor "реагирует" на сообщение, вы отправляете сообщение Reactor, Даже если вы явно не возвращаете значение, в Groovy последняя строка в Closure - это оператор return. В результате, поскольку ваша последняя строка в закрытии println, возврат этого равен нулю. Так что ваши Reactor возвращает ноль, что рассматривается как сообщение Actorи снова обработан.

Чтобы избежать этого сценария, вам необходимо оценить возвращаемое сообщение и делегировать сообщение или распечатать его, только если оно еще не было обработано. Я обновил ваш код и намеренно вернул "готово" в качестве сообщения для ясности. Вы можете изменить код, чтобы просто проверить null сообщение перед его обработкой:

импорт groovyx.gpars.actor.Actors

def a = 1
def b = 100000

def reactor2 = Actors.reactor { message ->
    if(!message.equals("done")) {
        println "\t\tReact Again: $message"
    }
    return "done"
}

def reactor = Actors.reactor { message ->
    if(!message.equals("done")) {
        println "\tReact: $message"
        reactor2 << message
    }
    return "done"
}

def actor = Actors.actor {
    loop {
        react {
            if(!it.equals("done")) {
                println it
                reactor << it
            }
        }
    }
}

(a..b).each {
    actor << it
    // actor.oi
}
actor.join()
Другие вопросы по тегам