10.10 在各种接收方法中选择

面临几个选择,会让人不知所措,所以,在本节里,我会帮你在receive()receiveWithin()react()reactWithin()中做出选择。

我们应该优先使用以Within结尾的方法,而不是其他的方法。调用receive()react()可能会导致失败。actor可能会为一个接收不到的消息永远等下去,因为发消息的actor可能已经退出,也可能出了问题,永远不再发消息了,或是执行了一个无效的操作导致了致命的异常。因此,应该使用receiveWithin()reactWithin(),以便在一段合理的时间内没有收到响应之后,能够优雅的恢复过来,采取适当的行动。

那么,什么时候该用receiveWithin(),什么时候该用reactWithin()呢?如果在一个工作流执行的中间,想要从另一个actor接收消息,那么receiveWithin()很合适。actor会一直阻塞,直到收到消息为止,收到之后继续。不过这种actor不要太多,因为每一个在结束之前都会持有一个线程。另一方面,如果想实现一个服务,接收消息,做一些操作,快速响应调用者(或另一个接收者),那么最好使用reactWithin()。它在等待消息到来期间,不会持有线程。这允许几个快速运行的任务或服务共享线程。如果尚不确定该用哪一个,就先用reactWithin(),只在reactWithin()不能满足需求时,再使用receiveWithin()。记住,要在loopWhile()里调用reactWithin(),以便actor可以持续处理更多的消息。这也有助于在需要时在actor里处理状态。如果倾向于使用函数式风格,也可以在reactWithin()里递归调用方法。如果reactWithin()里只有一两个case语句,后一种方式也可以。

结束本章之时,我希望你会如我一样,对Scala的并发编程设施留有深刻的印象。我们拥有了令人吃惊的能量,不必忍受同步和异常。只要做一个好公民——也就是说,只传不变对象——就不必顾虑竞争。Scala的高层抽象有助于让我们专注于手头的问题,把这些琐碎的细节交由语言处理。用bug更少、更简洁的代码,处理这种非常关键和复杂的问题。

我们可以用Scala构建整个应用,或是用Scala构建应用的某些部分——Scala提供了灵活的选择。如果我们有一个旧的Java应用,决定利用Scala在表现力、简洁、功能或是并发方面的优势,我们可以很轻松地将Scala同Java混合起来,这就是我们在下一章会看到的内容。