jjzjj

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

coder 2023-08-28 原文

我的模拟使用的是 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/

有关Scala Actor : Different behavior on JRE 1. 5 和 1.6的更多相关文章

  1. ruby-on-rails - 安装调试器(1.6.8)时出错,Bundler 无法继续。确保 `gem install debugger -v ' 1.6。 8'` - 2

    通过geminstalldebugger-v'1.6.8'安装调试器时似乎有递归效果,它说安装成功,但是当我执行bundleinstall时,消息再次出现或bundle更新|20:15:37|~geminstalldebugger-v'1.6.8'Buildingnativeextensions.Thiscouldtakeawhile...Successfullyinstalleddebugger-1.6.8Parsingdocumentationfordebugger-1.6.8unabletoconvert"\xCF"fromASCII-8BITtoUTF-8forlib/ruby

  2. javascript - Controller 内部的 Angular 1.6 绑定(bind) - 2

    我试图通过绑定(bind)将一些参数传递给我的组件,但不幸的是我没有在我的Controller中使用这些参数,这是我的代码:angular.module('project1').component('menu',{templateUrl:'/static/js/templates/menu.template.html',bindings:{rid:'@'},controller:['Restaurant',functionRestaurantListController(Restaurant){console.log(this.rid);console.log(this);this.r

  3. javascript - Angular 1.6 $http.jsonp 同时使用 google sheets API - 2

    Angular1.6的$http.jsonp与googlesheets的API不兼容:我正在尝试通过以下方式从谷歌表格中获取然后获取我的数据:varcallback;app.controller("meetingsTable",function($scope,$http,$sce){varurl="http://spreadsheets.google.com/a/google.com/tq";vartrustedUrl=$sce.trustAsResourceUrl(url);varkey='MY_KEY';vartq='select%20*%20limit%2010';vartqx=

  4. javascript - 如何设置默认 View 位置 (Cesium 1.6) - 2

    我想为cesium应用程序设置默认View/主页位置。我不只是想飞到那个地点一次;我希望将位置设置为默认/家-以便它可以在应用程序的其他地方使用-例如在HomeButton小工具。我试过设置Camera.DEFAULT_VIEW_RECTANGLE(docshere)像这样:varextent=Cesium.Rectangle.fromDegrees(117.940573,-29.808406,118.313421,-29.468825);viewer.camera.DEFAULT_VIEW_RECTANGLE=extent;但是没用..为了完整起见,下面是我初始化应用程序的方式:va

  5. JavaScript 1.6 Array.map() 和 Array.filter() 不使用内置函数作为参数 - 2

    这很好用:["655971","2343","343"].map(function(x){returnparseInt(x)})//[655971,2343,343]但这不是:["655971","2343","343"].map(parseInt)//[655971,NaN,NaN]Array.filter()也是如此我在这里错过了什么? 最佳答案 这是因为map向回调函数传递的参数不仅仅是数组项。你得到:callback(item,index,array)通常你的函数会忽略它不需要的参数。但是parseInt接受一个可选的第二个

  6. go - Go 1.5 和 1.6 中 yacc 的向后兼容性 - 2

    Lexshouldreturnthetokenidentifier,andplaceothertokeninformationinlval(whichreplacestheusualyylval).以上文字摘自godocument.我在yacc文件(some.y文件)的语法规则的Action部分使用了变量(yylval)。该代码在Go1.5中有效。但是相同的代码在Go1.6中无法编译。当我检查生成的y.go文件时(来自'goyacctoolsome.y'命令),Go在不同的版本中创建了不同的变量名。varyylvalyySymType//inG01.5varyyVALyySymType

  7. go - 构建 Go 1.6 的问题 - 2

    我正在尝试在linux中构建和安装go1.6。(amd64)。我已经安装了go1.42。我不断收到错误消息:构建dist时不允许导入周期。我已经从/usr/lib/golang/bin/go链接到/usr/bin。我设置了GOROOT_BOOTSTRAP=/usrGOARCH="amd64"GOBIN=""GOCHAR="6"GOEXE=""GOHOSTARCH="amd64"GOHOSTOS="linux"GOOS="linux"GOPATH="/usr/share/gocode"GORACE=""GOTOOLDIR="/usr/bin/pkg/tool/linux_amd64"GO

  8. golang 1.6交叉编译 - 2

    在golang1.6中,当我从64位arch交叉编译到32位Linux时,goinstall命令将可执行文件放入bin/linux_386/.有没有办法把它放到bin/反而?如果我在32位环境中构建,那么它将进入bin/.无论我是在沙箱外交叉编译为32位,还是在32位沙箱内进行native编译,我都希望exe进入同一位置。我现在的解决方法是软链接(softlink)linux_386目录.,如ln-s.linux_386. 最佳答案 你不能使用goinstall,但是你可以手动安装:gobuild-o$GOPATH/bin/$GOP

  9. java - 在 JDK 1.6 中验证失败,在 JDK 1.7 中验证成功 - 2

    我在使用非常基本的XSD验证xml时遇到了一个奇怪的问题。JDK1.6和JDK1.7的行为不一样...这是我的架构:这是我的XML:someContent为了验证,我使用了这个简单的程序:SchemaFactoryfactory=SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);Schemaschema=factory.newSchema(newSAXSource(newInputSource(newByteArrayInputStream(xsd.getBytes()))));Validatorvalidato

  10. xml - Magento 1.6 XML 错误 - 2

    我安装了Magento。当我用eclipse或ZendStudio打开它时,它会显示一堆与XML相关的错误。我不太清楚为什么会这样。有人知道如何解决这个问题吗?以下是前几个错误。但是大约有212个错误和1225个警告。--------------------------------------------------------------------------------------DescriptionResourcePathLocationTypecvc-attribute.3:Thevalue'{{varwsdl.handler}}Binding'ofattribute'na

随机推荐