我正在尝试使用scala actor来并行化代码。这是我的第一个真正的代码与演员,但我有一些Java Mulithreading和MPI在C中的经验。但我完全失去了。
我想要实现的工作流程是一个循环管道,可以描述如下:
StartWork()
消息来触发计算StartWork()
消息时,它会在本地处理一些内容并向该圈子中的邻居发送DoWork(...)
消息。DoWork(...)
消息发送给自己的邻居。DoWork()
消息。GetResult()
消息并等待回复。关键是协调员只应在数据准备好时收到结果。 在回复GetResult()
消息之前,工作人员如何等待作业返回?
为了加快计算速度,任何工作人员都可以随时收到StartWork()
。
这是我第一次尝试伪实现的worker:
class Worker( neighbor: Worker, numWorkers: Int ) {
var ready = Foo()
def act() {
case StartWork() => {
val someData = doStuff()
neighbor ! DoWork( someData, numWorkers-1 )
}
case DoWork( resultData, remaining ) => if( remaining == 0 ) {
ready = resultData
} else {
val someOtherData = doOtherStuff( resultData )
neighbor ! DoWork( someOtherData, remaining-1 )
}
case GetResult() => reply( ready )
}
}
在协调员方面:
worker ! StartWork()
val result = worker !? GetResult() // should wait
答案 0 :(得分:3)
首先,您显然需要有一些标识符来构成单件作品,以便GetResult
可以获得正确的结果。我想明显的解决方案是让你的演员保持Map
的结果和Map
任何等待的 getters :
class Worker( neighbor: Worker, numWorkers: Int ) {
var res: Map[Long, Result] = Map.empty
var gets: Map[Long, OutputChannel[Any]] = Map.empty
def act() {
...
case DoWork( id, resultData, remaining ) if remaining == 0 =>
res += (id -> resultData)
gets.get(id).foreach(_ ! res(id)) //reply to getters when result is ready
gets -= id //clear out getter map now?
case GetResult(id) if res.isDefinedAt(d) => //result is ready
reply (res(id))
case GetResult(id) => //no result ready
gets += (id -> sender)
}
}
注意:在匹配条件下使用if
可以使邮件处理更清晰
答案 1 :(得分:1)
另一种选择是:
class Worker( neighbor: Worker, numWorkers: Int ) {
var ready = Foo()
def act() {
case StartWork() => {
val someData = doStuff()
neighbor ! DoWork( someData, numWorkers-1 )
}
case DoWork( resultData, remaining ) => if( remaining == 0 ) {
ready = resultData
react {
case GetResult() => reply( ready )
}
} else {
val someOtherData = doOtherStuff( resultData )
neighbor ! DoWork( someOtherData, remaining-1 )
}
}
}
工作完成后,此工作人员将被卡住,直到收到GetResult
消息。另一方面,协调员可以立即发送GetResult
,因为它将保留在邮箱中,直到工作人员收到它。