我对Scala完全不熟悉,而且我一直在通过 Programming 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%的时间,我根本没有输出,甚至更少,我只得到第一行作为输出。我不太了解Scala还不知道这是否正常,因为Actors的工作方式,或者我的Scala安装可能出错(Arch Linux上的Scala 2.8.1)。
演员是否无法处理此类消息(可能是因为编写示例的方式)?或者还有其他事情我可能会在这里失踪吗?
答案 0 :(得分:5)
我相信Scala REPL在完成脚本运行时正在使用System.exit(...)。这将在不等待任何挥之不去的线程的情况下停止该过程。
这意味着所有消息都将被发送给actor,但是actor可能无法及时处理它们。
为了演示您可能尝试将Thread.sleep(1000)添加到shapes-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秒的松弛)它应该每次都成功。
解决方案是使用一个不以System.exit(...)结尾的程序。
更新(秒想法):
您还可以将actor设置为在退出时通知:
case "exit" => Thread.sleep(1000);println("exiting..."); this.synchronized { this.notify }; exit
...然后脚本可以等待通知:
ShapeDrawingActor.synchronized { ShapeDrawingActor.wait(10000) }
答案 1 :(得分:1)
很抱歉回复这个帖子的时间很长(因为我在书中写了这个例子:^ /)。我认为真正的问题是STDOUT在所有OS(和shell?)环境中都没有默认刷新,并且行为似乎因Scala的版本而异。今晚,我使用2.7.7编译并运行代码。 OS X(10.6.6),Java 1.6.0_24-b07-334-10M3326和bash上的2.8.0和2.8.1。
对于2.7.7和2.8.1,在退出流程之前打印所有输出。对于2.8.0,只出现了一些输出!当我将“System.out.flush”添加到shapes-actor-script.scala的末尾时,所有输出都打印为2.8.0。
答案 2 :(得分:0)
实际上,这似乎足够合理。请参阅,actor与脚本并发,脚本中没有任何行等待答案。因此,在演员决定处理任何消息之前,很有可能将许多消息传递给演员。
然后归结为演员如何通过其邮箱。它可以作为队列进行处理。但它也可以随机地通过它,这提供了一些有趣的属性。
我的猜测是,Scala 2.7.x是本书编写时可用的版本,默认使用排队算法,而版本2.8.1使用随机算法。
答案 3 :(得分:0)
简单的解决方案,将其添加到shapes-actor-script.scala:
的末尾Thread.sleep(1000)
它会让演员有时间在REPL终止之前打印所有各种Shape消息。