Scala actors:receive vs react

19 浏览
0 Comments

Scala actors:receive vs react

首先,让我说一下我有相当多的Java经验,但最近才对函数式语言产生了兴趣。最近我开始研究Scala,这是一种非常好的语言。\n然而,我在《Scala编程》中读到了关于Scala的Actor框架的一点不理解。在第30.4章中,它说使用react而不是receive可以重用线程,这对性能很有好处,因为JVM中的线程很昂贵。\n这是否意味着只要我记得调用react而不是receive,我可以启动任意数量的Actor?在发现Scala之前,我一直在尝试Erlang,并且<《编程Erlang》的作者吹嘘说他可以轻松启动超过20万个进程。我不愿意用Java线程做这件事。与Erlang(和Java)相比,Scala有什么限制?\n此外,Scala中的线程重用是如何工作的?为了简单起见,假设我只有一个线程。我启动的所有Actor是否会在此线程中串行运行,还是会发生某种形式的任务切换?例如,如果我启动两个互相发送消息的Actor,如果它们在同一个线程中启动,会有死锁风险吗?\n根据《Scala编程》的说法,编写使用react的Actor比使用receive更困难。这听起来很有道理,因为react不会返回。然而,该书继续展示了如何使用Actor.loop在循环中放置react。结果,你会得到:\n

loop {
    react {
        ...
    }
}

\n对我来说,这似乎与之前在书中使用的\n

while (true) {
    receive {
        ...
    }
}

\n非常相似。然而,该书说“实际上,程序至少需要几个receive”。那么我在这里漏掉了什么?除了返回之外,receive能做什么react不能做?为什么我要关心呢?\n最后,谈到我不理解的核心问题:该书一直提到使用react可以丢弃调用堆栈以重用线程。这是如何工作的?为什么需要丢弃调用堆栈?为什么当函数通过抛出异常(react)终止时可以丢弃调用堆栈,而当函数通过返回(receive)终止时不能丢弃呢?\n我有一种印象,《Scala编程》在这里掩盖了一些关键问题,这很可惜,因为除此之外,这是一本真正优秀的书。

0
0 Comments

Scala actors是一个用于并发编程的库,其中有两个常用的方法receive和react。这两个方法的出现是为了解决不同的问题。

receive方法是一个阻塞方法,它会一直等待直到接收到消息。在这个方法中,线程的整个堆栈都是可用的,并且可以从等待接收消息的点继续执行。例如,在下面的代码中,线程将在receive调用中等待,直到接收到消息,然后继续执行并打印出"after receive and printing a 10"的消息,并且打印出之前在堆栈帧中的值10。

def a = 10;
while (! done)  {
    receive {
        case msg =>  println("MESSAGE RECEIVED: " + msg)
    }
    println("after receive and printing a " + a)
}

而react方法没有专门的线程,相反,react方法的整个方法体被作为闭包捕获,并由相应的actor在接收到消息时执行。这意味着只有那些可以作为独立闭包执行的语句将被执行,这也是为什么react方法的返回类型是"Nothing"的原因。考虑下面的代码,在react调用之后的语句(例如打印消息"after react and printing a 10"的println语句)实际上永远不会被执行,因为只有react方法的方法体会被捕获并按顺序在稍后执行(在接收到消息时)。由于react的契约具有返回类型"Nothing",所以不能在react之后有任何语句,因此也没有必要维护堆栈。在上面的例子中,变量"a"不需要维护,因为react调用之后的语句根本不会被执行。需要注意的是,react方法的方法体已经作为闭包捕获了所有需要的变量,所以它可以正常执行。

def a = 10;
while (! done)  {
    react {
        case msg =>  println("MESSAGE RECEIVED: " + msg)
    }
    println("after react and printing a " + a) 
}

需要注意的是,Java actor框架Kilim通过保存堆栈来实现堆栈维护,当react收到消息时,堆栈将被展开。

receive和react方法的出现是为了解决不同的并发编程问题。receive方法是一个阻塞方法,它等待接收消息并使用整个线程堆栈来继续执行。而react方法没有专门的线程,它的方法体被作为闭包捕获,并在接收到消息时执行。由于react方法的契约具有返回类型"Nothing",所以不能在react之后有任何语句,因此也没有必要维护堆栈。

0
0 Comments

Scala actors: receive vs react的问题的出现原因是为了避免出现StackOverflowError错误,需要丢弃调用堆栈。通过使用react方法,框架巧妙地抛出SuspendActorException异常,然后被循环代码捕获并通过andThen方法再次运行react。

解决方法是通过使用react方法来代替receive方法来处理消息。react方法会丢弃调用堆栈,避免出现StackOverflowError错误。在Actor类的mkBody方法和seq方法中可以看到循环如何重新调度自身的代码。

代码示例:

import scala.actors.Actor
class MyActor extends Actor {
  def act() {
    loop {
      react {
        case message => // 处理消息的代码
      }
    }
  }
}

以上是关于Scala actors: receive vs react问题的原因和解决方法的文章。

0
0 Comments

Scala actors中的问题:receive vs react

在Scala actors中,存在一个问题,即使用receive和react两种方式进行消息接收的不同。这个问题的出现主要是由以下原因引起的,并且可以通过解决方法来解决。

首先,每个使用receive方式等待的actor都占用一个线程。如果它从来没有接收到任何消息,那么该线程将永远不会执行任何操作。而使用react方式的actor在没有接收到消息之前不占用任何线程。一旦它接收到消息,一个线程就会被分配给它,并在其中进行初始化。

现在,初始化部分是很重要的。接收线程需要返回一些内容,而反应线程不需要。因此,在上一个react结束时,前一个堆栈状态可以完全丢弃。不需要保存或恢复堆栈状态使得线程启动更加快速。

有各种性能原因可能会选择其中一种方式。正如你所知,使用过多的线程在Java中并不是一个好主意。另一方面,因为你必须在actor可以react之前将其附加到一个线程上,所以使用receive接收消息比使用react反应消息更快。因此,如果你的actor接收到许多消息但对其处理很少,那么react的额外延迟可能会使其速度变慢,不适合你的目的。

解决方法可能是根据具体情况选择使用receive或react方式。如果需要高性能且不关心消息处理的结果,可以选择使用react方式。如果需要及时返回结果并且消息处理量较小,则可以选择使用receive方式。根据应用场景的不同,选择合适的方式可以提高程序的性能和效率。

0