jqn*_*qno 110 multithreading scala actor
首先我要说的是,我有很多Java经验,但最近才对函数式语言感兴趣.最近我开始关注Scala,这似乎是一种非常好的语言.
但是,我一直在阅读Scala 编程中的 Scala的Actor框架,有一点我不明白.在第30.4章中,它表示使用react而不是receive可以重用线程,这对性能有好处,因为线程在JVM中很昂贵.
这是否意味着,只要我记得打电话react而不是receive,我可以开始尽可能多的演员?在发现Scala之前,我一直在和Erlang一起玩,编程Erlang的作者自豪地生成了超过20万个进程,而且不会出汗.我讨厌用Java线程做到这一点.与Erlang(和Java)相比,我在Scala中看到了什么样的限制?
此外,此线程如何在Scala中重用?为简单起见,我们假设我只有一个线程.我开始的所有演员都会在这个帖子中按顺序运行,还是会进行某种任务切换?例如,如果我启动两个互相ping消息的actor,如果它们在同一个线程中启动,我是否会冒死锁?
根据Scala编程,编写演员使用react比使用更困难receive.这听起来似乎有道理,因为react不会回来.然而,本书接着展示了如何react使用循环内部Actor.loop.结果,你得到了
loop {
react {
...
}
}
Run Code Online (Sandbox Code Playgroud)
对我来说,这看起来非常相似
while (true) {
receive {
...
}
}
Run Code Online (Sandbox Code Playgroud)
在本书前面使用过.尽管如此,这本书还是说"在实践中,程序至少需要少数几个receive".那我在这里错过了什么?除了回归之外,receive做什么不能做到react?为什么我关心?
最后,进入我不理解的核心:本书不断提及如何使用react可以丢弃调用堆栈来重用线程.这是如何运作的?为什么有必要丢弃调用堆栈?当函数通过抛出异常(react)而终止时,为什么可以放弃调用堆栈,而不是当它通过返回(receive)终止时?
我的印象是Scala中的Programming一直在掩盖这里的一些关键问题,这是一种耻辱,因为否则它是一本真正优秀的书.
Dan*_*ral 78
首先,每个等待的玩家receive都占据一个线程.如果它从未收到任何东西,该线程将永远不会做任何事情.演员on在react收到某些东西之前不会占用任何线程.一旦收到某个东西,就会为它分配一个线程,并在其中初始化.
现在,初始化部分很重要.接收线程应该返回一些东西,一个反应线程不会.因此,最后一个末尾的堆栈状态react可以完全丢弃.无需保存或恢复堆栈状态使线程更快启动.
您可能需要其中一个或多个的各种性能原因.如您所知,Java中包含太多线程并不是一个好主意.另一方面,因为你必须先将一个actor附加到一个线程react,所以它对receive消息的速度要快react于它.因此,如果您的演员收到许多消息但很少使用它,那么额外的延迟react可能会使您的目的太慢.
oxb*_*kes 21
答案是"是" - 如果你的演员没有阻止代码中的任何东西并且你正在使用react,那么你可以在一个线程中运行你的"并发"程序(尝试设置系统属性actors.maxPoolSize以找出).
有必要丢弃调用堆栈的一个更明显的原因是,否则该loop方法将以a结尾StackOverflowError.实际上,框架相当巧妙地react通过抛出a来结束SuspendActorException,循环代码然后react通过该andThen方法再次运行.
看看mkBody方法Actor,然后seq看方法,看看循环如何重新安排自己 - 非常聪明的东西!
Ash*_*win 20
那些"丢弃堆栈"的陈述让我感到困惑了一段时间,我想我现在得到它,这是我现在的理解.在"接收"的情况下,在消息上有一个专用的线程阻塞(在监视器上使用object.wait()),这意味着完整的线程堆栈可用并准备好从接收到"等待"的点继续信息.例如,如果您有以下代码
def a = 10;
while (! done) {
receive {
case msg => println("MESSAGE RECEIVED: " + msg)
}
println("after receive and printing a " + a)
}
Run Code Online (Sandbox Code Playgroud)
线程将在接收呼叫中等待,直到收到消息,然后继续打开并在线程被阻止之前打印"接收并打印10"消息并且值为"10".
如果没有这样的专用线程,则反应方法的整个方法体被捕获为闭包,并由接收消息的相应actor上的某个任意线程执行.这意味着只有那些可以作为闭包单独捕获的语句才会被执行,并且这就是"Nothing"的返回类型所在的位置.请考虑以下代码
def a = 10;
while (! done) {
react {
case msg => println("MESSAGE RECEIVED: " + msg)
}
println("after react and printing a " + a)
}
Run Code Online (Sandbox Code Playgroud)
如果react有返回类型的void,则意味着在"react"调用之后有语句是合法的(在示例中println语句打印消息"在反应并打印10"之后),但实际上永远不会被执行,因为只有"反应"方法的主体被捕获并排序以便稍后执行(在消息到达时).由于react的契约具有返回类型"Nothing",因此不能有任何语句响应,并且没有理由维持堆栈.在上面的示例中,变量"a"不必保持为在根本不执行react调用之后的语句.请注意,反应主体所需的所有变量已经被捕获为闭包,因此它可以执行得很好.
java actor框架Kilim实际上通过保存堆栈来进行堆栈维护,该堆栈在获取消息的反应中展开.
| 归档时间: |
|
| 查看次数: |
17867 次 |
| 最近记录: |