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的范围越来越宽,越来越容易发生这种错误。但当范围有限时,该错误永远不会发生。
我不明白为什么会发生这个错误。
发布于 2016-05-08 03:20:40
从您提供的代码示例中,我不能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中,闭包中的最后一行是return语句。因此,由于闭包中的最后一行是println,因此它的返回值为空。因此,您的Reactor返回null,它被视为发送给Actor的消息,并再次进行处理。
为了避免这种情况,您需要评估返回的消息,并仅委托该消息/或者如果该消息尚未处理,则打印该消息。我已经更新了你的代码,为了清楚起见,我特意返回了'done‘作为返回消息。您可以将代码更改为在处理之前只检查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()https://stackoverflow.com/questions/37089361
复制相似问题