While模式严格来说是while循环在Akka中的合理实现。while是开发过程中经常用到的语句之一,也是绝大部分编程语言都支持的语法。但while语句是一个循环,如果循环条件没有达到会一直执行while语句体的代码,且会阻塞while语句外的代码。如果在Akka中简单的使用while语句会极大的限制当前actor的功能。
object GeneralWhile { def main(args: Array[String]): Unit = { var i=0 val maxLine = 10 while(i<maxLine){ println(i) i += 1 } } }
输出:
0 1 2 3 4 5 6 7 8 9
上图是while语句的常规用法,打印了从0-9的数字。如果这段代码出现在了actor对某个消息的处理过程中,就会带来其他的问题和不便。
class WhileActor extends Actor{ override def receive: Receive = { case "start" => println("do start work") var i=0 val maxLine = 10 while(i<maxLine){ println(i) i += 1 } println("start work done") case "others" => println("do other work") } } object WhilePattern1 { def main(args: Array[String]): Unit = { val system = ActorSystem("WhilePattern1",ConfigFactory.load()) val whileActor = system.actorOf(Props(new WhileActor),"WhilePattern1") whileActor ! "start" whileActor ! "others" } }
输出:
do start work 0 1 2 3 4 5 6 7 8 9 start work done do other work
上面代码是actor中简单使用while的例子。其实在简单的业务场景下,这种实现并没有太大问题,只不过while可能会阻塞当前actor而已。不过while有一个极端的情况,那就是while死循环。虽然死循环不能轻易出现,不过也非常有用。比如有以下场景:循环读取数据库做某种操作。在Akka的消息处理过程中是绝对不能出现死循环的,一旦出现死循环这个actor基本就废了(因为阻塞到了这个方法处理)!
其实如果你的业务需求需要在Akka中使用死循环,而且你也的确这么用了,那只能说明对Actor模型不熟悉,因为Actor模型本身对消息的处理就是“死循环”。为什么说actor本身就是一个“死循环"呢?actor在收到消息会进行对应的处理,死循环也就意味着一直收到消息,那么如何一直收到消息呢?其他actor给它发消息或者自己给自己发消息,很显然,actor内部的循环逻辑跟其他actor关系不大,发消息给自己是比较合理的。
class WhileForeverActor extends Actor{ var condition = true override def preStart(): Unit = { super.preStart() self ! "doWork" } override def receive: Receive = { case "doWork" => println("从数据库获取n条数据循环处理") Thread.sleep(1000) println("处理完毕") if(condition){ self ! "doWork" } case "otherWork" => println("处理其他消息") } } object WhilePattern2 { def main(args: Array[String]): Unit = { val system = ActorSystem("WhilePattern2",ConfigFactory.load()) val whileActor: ActorRef = system.actorOf(Props(new WhileForeverActor),"WhilePattern2") Thread.sleep(3*1000) whileActor ! "otherWork" whileActor ! "otherWork" } }
输出:
从数据库获取n条数据循环处理 处理完毕 从数据库获取n条数据循环处理 处理完毕 从数据库获取n条数据循环处理 处理完毕 处理其他消息 处理其他消息 从数据库获取n条数据循环处理 处理完毕 从数据库获取n条数据循环处理 处理完毕 从数据库获取n条数据循环处理 处理完毕 从数据库获取n条数据循环处理
上面是Akka中的while模式。简单点说,就是用自身消息驱动acotor的循环处理。这样做的好处就是可以在某次循环结束后及时的处理其他类型的消息,而不至于阻塞当前的actor,而且可以随时通过发消息的形式中断循环或修改循环条件。
本文介绍了Akka中的while设计模式,该模式虽然简单,但也都是Akka初学者经常会遇到也最容易设计不当的情形。希望大家好好掌握该设计模式,设计出更优秀的代码。