mei*_*eip 16 java scala scala-2.8 actor
我的模拟是使用actor和Scala 2.8-Snapshot.在Java JRE 1.5中它运行良好 - 所有40个齿轮(演员)同时工作.使用Java JRE 1.6只有3个齿轮同时工作.我使用和不使用GUI进行测试:两者都给出相同的结果.
我在GUI上的模拟可以在github上找到:http://github.com/pmeiclx/scala_gear_simulation
也许你还记得我与演员的第一个问题.在解决了这些问题后,我为模拟做了一个GUI,我得到了这种新的"奇怪"行为.
这是没有GUI的代码:
package ch.clx.actorversions
import actors.Actor
import actors.Actor._
import collection.mutable.ListBuffer
case class ReceivedSpeed(gear: Gear)
case object StartSync
case class SyncGear(controller: GearController, syncSpeed: Int)
object ActorVersion {
def main(args:Array[String]) = {
println("[App] start with creating gears")
val gearList = new ListBuffer[Gear]()
for (i <- 0 until 100) {
gearList += new Gear(i)
}
val gearController = new GearController(gearList)
gearController.start()
gearController ! StartSync
}
}
/**
* CONTROLLER
*/
class GearController(nGears: ListBuffer[Gear]) extends Actor {
private var syncGears = new ListBuffer[Gear]
private var syncSpeed = 0
def act = {
while(true) {
receive {
case StartSync => {
println("[Controller] Send commands for syncing to gears!")
var speeds = new ListBuffer[Int]
nGears.foreach(e => speeds += e.speed)
//Calc avg
//var avgSpeed = speeds.foldLeft(0)(_ + _) / speeds.length
//var avgSpeed = speeds.foldLeft(0) { (x, y) => x + y } / speeds.length
syncSpeed = (0/:speeds)(_ + _) / speeds.length //Average over all gear speeds
//TODO syncSpeed auf Median ausrichten
println("[Controller] calculated syncSpeed: "+syncSpeed)
nGears.foreach{e =>
e.start()
e ! SyncGear(this, syncSpeed)
}
println("[Controller] started all gears")
}
case ReceivedSpeed(gear: Gear) => {
println("[Controller] Syncspeed received by a gear ("+gear.gearId+")")
//println("[Controller] mailboxsize: "+self.mailboxSize)
syncGears += gear
if(syncGears.length == nGears.length) {
println("[Controller] all gears are back in town!")
System.exit(0)
}
}
case _ => println("[Controller] No match :(")
}
}
}
}
/**
* GEAR
*/
class Gear(id: Int) extends Actor {
private var mySpeed = scala.util.Random.nextInt(1000)
private var myController: GearController = null
def speed = mySpeed
def gearId = id
/* Constructor */
println("[Gear ("+id+")] created with speed: "+mySpeed)
def act = {
loop {
react {
case SyncGear(controller: GearController, syncSpeed: Int) => {
//println("[Gear ("+id+")] activated, try to follow controller command (form mySpeed ("+mySpeed+") to syncspeed ("+syncSpeed+")")
myController = controller
adjustSpeedTo(syncSpeed)
}
}
}
}
def adjustSpeedTo(targetSpeed: Int) = {
if(targetSpeed > mySpeed) {
mySpeed += 1
self ! SyncGear(myController, targetSpeed)
}else if(targetSpeed < mySpeed) {
mySpeed -= 1
self ! SyncGear(myController, targetSpeed)
} else if(targetSpeed == mySpeed) {
callController
}
}
def callController = {
println("[Gear ("+id+")] has syncSpeed")
myController ! ReceivedSpeed(this)
}
}
Run Code Online (Sandbox Code Playgroud)
简答:更改控制器以使用循环/反应而不是while/receive
actors库检测它正在运行哪个Java版本,如果它是1.6(而不是IBM的VM),它使用捆绑版本的JSR-166y fork join线程池,因此底层实现存在很大差异,具体取决于Java版本.
fork/join线程池使用一种两级队列来执行任务.每个工作线程都有一个队列,并且池中有一个共享队列.源自fork/join线程的任务直接进入fork/join线程的队列,而不是通过主队列.线程之间的任务窃取用于保持线程忙,并帮助避免饥饿.
在您的情况下,启动齿轮的所有任务最终都会在运行控制器的线程的队列中结束.因为您在该actor中使用while/receive,所以它永远不会放弃该线程,因此它永远不会直接在其队列上执行任务.其他线程经常忙于3档,因此他们从不试图从运行控制器的线程中窃取工作.结果是其他齿轮演员从未被执行过.
切换到控制器中的循环/响应应该可以解决问题,因为在每个循环中,actor都会释放线程并调度一个新任务,该任务最终将在队列的后面,以便执行其他任务.
归档时间: |
|
查看次数: |
897 次 |
最近记录: |