【问题标题】:Can Actors in Scala fail to process messages? (example in O'Reilly's Programming Scala)Scala 中的 Actor 会无法处理消息吗? (O'Reilly 的 Programming Scala 中的示例)
【发布时间】:2011-01-26 20:16:47
【问题描述】:

我对 Scala 完全陌生,我一直在通过 Scala 编程 (O'Reilly) 在线工作;这样做时,我对Chapter 1, "A Taste Of Concurrency" 中的shapes-actor-script.scala 示例的结果感到惊讶。

具体来说,运行scala -cp . shapes-actor-script.scala的输出应该是:

Circle.draw: Circle(Point(0.0,0.0),1.0)
Rectangle.draw: Rectangle(Point(0.0,0.0),2.0,5.0)
Triangle.draw: Triangle(Point(0.0,0.0),Point(1.0,0.0),Point(0.0,1.0))
Error: Unknown message! 3.14159
exiting...

然而,大约 10% 的情况下,我根本没有得到任何输出,甚至更罕见的是,我只会得到第一行作为输出。由于 Actor 的工作方式,我对 Scala 的了解还不够,不知道这是否正常,或者我的 Scala 安装(Arch Linux 上的 Scala 2.8.1)是否有问题。

Actor 是否会无法处理这样的消息(可能是因为示例的编写方式)?或者还有什么我可能在这里遗漏的事情?

【问题讨论】:

    标签: scala actor


    【解决方案1】:

    我相信 Scala REPL 在完成脚本运行后正在使用 System.exit(...)。这将停止该过程,而无需等待任何挥之不去的线程。

    这意味着所有消息都会发送给actor,但actor可能无法及时处理。

    为了演示,您可以尝试将 Thread.sleep(1000) 添加到 shape-actor.scala 中的每个案例:

    case s: Shape => Thread.sleep(1000);s.draw()
    case "exit"   => Thread.sleep(1000);println("exiting..."); exit
    case x: Any   => Thread.sleep(1000);println("Error: Unknown message! " + x)
    

    这可能会使脚本每次都失败(它在我的机器上)。如果你然后添加 Thread.sleep(5000) (给 2 秒的 slack)它应该每次都成功。

    解决方案是使用不以 System.exit(...) 结尾的程序。

    更新(三思而后行):

    您还可以设置参与者在退出时通知:

    case "exit"   => Thread.sleep(1000);println("exiting..."); this.synchronized { this.notify }; exit
    

    ...然后脚本可以等待通知:

    ShapeDrawingActor.synchronized { ShapeDrawingActor.wait(10000) }
    

    【讨论】:

      【解决方案2】:

      很抱歉回复这个帖子的时间很长(因为我在书中写了这个例子:^/)。我相信真正的问题是所有操作系统(和外壳?)环境中默认情况下都不会刷新 STDOUT,并且行为似乎因 Scala 的版本而异。今天晚上,我使用 2.7.7 编译并运行了代码。 OS X (10.6.6) 上的 2.8.0 和 2.8.1、Java 1.6.0_24-b07-334-10M3326 和 bash。

      对于 2.7.7 和 2.8.1,所有输出都在进程退出之前打印。对于 2.8.0,只出现了一些输出!当我将“System.out.flush”添加到shapes-actor-script.scala 的末尾时,所有输出都是针对2.8.0 打印的。

      【讨论】:

        【解决方案3】:

        实际上,这似乎很合理。看,演员和剧本是并发的,剧本中没有一行等待回答。因此,在 Actor 决定处理其中任何一条消息之前,很多消息都已交付给 Actor 是完全可能的。

        然后归结为演员应该如何通过其邮箱。它可以通过它作为一个队列。但它也可以随机通过它,这提供了一些有趣的特性。

        我的猜测是 Scala 2.7.x 是本书编写时可用的版本,默认使用排队算法,而 2.8.1 版本使用随机算法。

        【讨论】:

        • 演员邮箱即使在 2.8.1 中也是一个队列(查看源代码)。
        【解决方案4】:

        简单的解决方案,将这个添加到shapes-actor-script.scala的末尾:

        Thread.sleep(1000)
        

        它会给参与者时间在 REPL 终止之前打印所有不同的 Shape 消息。

        【讨论】:

          猜你喜欢
          • 2010-11-03
          • 1970-01-01
          • 2014-11-10
          • 1970-01-01
          • 2012-09-06
          • 2015-01-06
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多