gpt4 book ai didi

Scala Actor : Different behavior on JRE 1. 5 和 1.6

转载 作者:太空狗 更新时间:2023-10-29 22:47:33 25 4
gpt4 key购买 nike

我的模拟使用的是 actors 和 Scala 2.8-Snapshot。在 Java JRE 1.5 中它运行良好——所有 40 个齿轮(参与者)同时工作。使用 Java JRE 1.6 只有 3 个齿轮同时工作。我在使用和不使用 GUI 的情况下对其进行了测试:两者都给出了相同的结果。

我的 GUI 模拟在 github 上可用:http://github.com/pmeiclx/scala_gear_simulation

也许你记得my first problem with actors .解决这些问题后,我为模拟做了一个 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)
}
}

最佳答案

简短回答:将 Controller 更改为使用循环/ react 而不是 while/接收

actors 库检测它运行在哪个 Java 版本上,如果是 1.6(而不是 IBM 的 VM),它使用捆绑版本的 JSR-166y fork join 线程池,因此在底层存在实质性差异实现取决于 Java 版本。

fork/join 线程池使用一种两级队列来处理任务。每个工作线程都有一个队列,池中有一个共享队列。源自 fork/join 线程的任务直接进入 fork/join 线程的队列,而不是通过主队列。线程间的任务窃取用于保持线程忙碌并帮助避免饥饿。

在您的情况下,启动齿轮的所有任务最终都会排队等待运行 Controller 的线程。因为您在那个 actor 中使用 while/receive 它永远不会释放线程,所以它永远不会直接在其队列上执行任务。其他线程一直忙于 3 个齿轮,因此它们从不尝试从运行 Controller 的线程窃取工作。结果是其他 gear actor 永远不会执行。

在 Controller 中切换到循环/ react 应该可以解决这个问题,因为在每个循环中,actor 都会放开线程并安排一个新任务,该任务将最终排在队列的后面,因此其上的其他任务将执行。

关于Scala Actor : Different behavior on JRE 1. 5 和 1.6,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2288723/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com