`

Scala.Actor实践心得与设计思想

 
阅读更多

   这段时间系统的学习了Scala,编程思想上可谓收获不少,想从里面挑些值得写的东西分享给大家,Scala的Actor

可谓这门语言的一个亮点,函数式编程核心价值在于多核编程,所以就打算说说这个Actor,总结一下学习心得。先很俗

套的简单谈谈概念,然后会拿四个例子做补充。主要内容包括基本原理,设计思想,单机环境并发测试。

 

 

            Actor是一种基于事件的轻量级线程,在以前的并发模型中,我们需要关注共享的数据结构,而使用Actor则需要

关注操作数据的代码结构,因为减少了数据的共享。Actor的主要能力来源于消息传递,而不是采用阻塞调用的处理形式。

如果创建直接或间接扩展 Actor的类,要确保对对象的所有调用都通过消息传递进行。

 

     我把Actor的设计思想归为两类,使用目的归为两类。从设计思想上来说Scala推荐的是以消息传递为核心的设计

思想,由于Scala可以无缝使用Java类库,所以也可以采用以共享数据为核心的设计,当然也可以写出混合式设计风格的

。使用目的主要有两种,一种是Scala提供APIJava调用,另一种就是Scala自给自足。举三个例子,例子很简单,是一

个累加器。

 

1、以消息传递为核心的设计:使用Actoractor方法,使用不可变对象,不考虑数据共享问题,以消息传递为设计核心。

 

复制代码
 1 import actors._, Actor._
 2 /*
 3  * Author:ShiYang
 4  * Blog:http://shiyangxt.cnblogs.com
 5  * */
 6 object SendMessageStyle {
 7 
 8   def main(args: Array[String]): Unit = {
 9     val caller = self
10     val accumulator = actor {
11       var continue = true
12       var sum = 0
13       loopWhile(continue) {
14         reactWithin(500) {
15           case number: Int => sum += number
16           case TIMEOUT =>
17             continue = false
18             caller ! sum
19         }
20       }
21     }
22     accumulator ! 1
23     accumulator ! 2
24     accumulator ! 3
25     receiveWithin(1000) {
26       case result => println("Total is " + result)
27     }
28   }
29 }
复制代码

 

2、以共享数据为核心的设计:构建由Actor继承共享数据操作类,以共享数据为核心。

 

复制代码
 1 import actors._, Actor._
 2 
 3 /*
 4  * Author:ShiYang
 5  * Blog:http://shiyangxt.cnblogs.com
 6  * */
 7 object SharedDataStyle {
 8   case class Add(number: Int)
 9   case class GetResult(sender: Actor)
10 
11   class AddActor extends Actor {
12     override def act(): Unit = process(0)
13     def process(value: Int): Unit = {
14       reactWithin(500) {
15         case Add(number) => process(value + number)
16         case GetResult(a) => a ! value; process(value)
17         case _ => process(value)
18       }
19     }
20   }
21 
22   def main(args: Array[String]): Unit = {
23     val addActor = new AddActor
24     addActor.start()
25     addActor ! Add(1)
26     addActor ! Add(2)
27     addActor ! Add(3)
28     addActor ! GetResult(self)
29     receiveWithin(1000) {
30       case result => println("Total is " + result)
31     }
32   }
33 }
复制代码

 

3、以API形式提供给Java程序使用:由于Java不能直接向Actor发消息,所以需要对Scala!()方法进行封装。

 

复制代码
 1 import actors._, Actor._
 2 /*
 3  * Author:ShiYang
 4  * Blog:http://shiyangxt.cnblogs.com
 5  * */
 6 object ForJavaStyle {
 7   case class Add(number: Int)
 8   case class GetResult(sender: Actor)
 9   private class AddActor extends Actor {
10     override def act(): Unit = process(0)
11     def process(value: Int): Unit = {
12       reactWithin(500) {
13         case Add(number) => process(value + number)
14         case GetResult(a) => a ! value; process(value)
15         case _ => process(value)
16       }
17     }
18   }
19   private val addActor = new AddActor
20   addActor.start()
21   private def add(sender: Actor, num: Int): Unit = {
22     sender ! Add(num)
23   }
24   private def getResult(sender: Actor): Int = {
25     sender ! GetResult(self)
26     receiveWithin(1000) {
27       case result: Int => result
28     }
29   }
30   def addForJava(num: Int): Unit = {
31     add(addActor, num)
32   }
33   def getResultForJava(): Int = {
34     getResult(addActor)
35   }
36 }
复制代码

 

Java端调用代码:

 

复制代码
 1 /*
 2  * Author:ShiYang
 3  * Blog:http://shiyangxt.cnblogs.com
 4  * */
 5 public class GetFromScala {
 6 
 7     public static void main(String[] args) {
 8         ForJavaStyle$.MODULE$.addForJava(1);
 9         ForJavaStyle$.MODULE$.addForJava(2);
10         ForJavaStyle$.MODULE$.addForJava(3);
11         System.out.println("Total is "
12                 + ForJavaStyle$.MODULE$.getResultForJava());
13     }
14 }
复制代码

 

      通过上面的例子可见ScalaJava语言有非常大的补充,提高了生产力。为Java提供了轻松实现多核并行编程的能

力。为了进一步测试Actor的并发性能,于是做了一个简单的单机环境并发测试。程序是构建一个Actor动态有序数组,

并发创建NActor对象,为了证明这些对象全都可用,顺序从数组的第一个Actor发消息到最后一个Actor,只有当一个

Actor接收到前一个Actor发送的消息后,才向后一个Actor发送消息。当最后一个数组元素接收到消息后,再把消息从数组

尾部用同样处理过程逆序发送到数组头部。这个消息发送过程不是并发处理,是顺序处理。这里只是为了证明这些对象全都

可用。如果为了测试并发处理,可以修改程序,让每个数组元素给后一位数组元素发消息。这样就会看到输出混乱的发送信

息,因为并发是无序的。

 

测试环境:双核4G内存,Windows XPSun JVM1.6,单机环境,Scala版本2.9.0.1

 

测试结果:当使用Receive方法接收消息时,由于Receive会在结束任务前一直持有线程,而Scala在后台默认只给Receive

方法启动256个线程,我的程序又是顺序的发消息,而且不是临时接收器(只处理一次消息),所以Receive在这种情况下,

只有255个并发。React接收器由于不需要长期持有线程,空闲即释放线程。所以React在本程序中可以跑20w的并发,如果

简单优化一下JVM,就可以达到100w的并发量。默认React接收器后台会调用4个线程组成的线程池。如果修改程序让每个数

组元素给后一位数组元素并发的发消息,那么在不阻塞线程的情况下,Receive方法也可以达到和React一样的并发量。因为

这个测试程序是顺序发送消息,所以就没有设置超时,如果是并发环境,建议加上超时,避免线程阻塞。

 

下面是测试程序:

 

复制代码
 1 import actors._, Actor._, java.util._
 2 /*
 3  * Author:ShiYang
 4  * Blog:http://shiyangxt.cnblogs.com
 5  * */
 6 object ConcurrentTest {
 7 
 8   val actors = new ArrayList[Actor]
 9   val length = 1000000
10   var startTime = System.nanoTime
11 
12   def main(args: Array[String]): Unit = {
13     for (i <- 0 to length)
14       actors.add(actor {
15         info("react: " + i + " actor created")
16         reactMessage
17       })
18     actors.get(0! (00)
19   }
20 
21   def info(msg: String) = println(msg + " received by " +
22     Thread.currentThread)
23 
24   def receiveMessage {
25     var continue = true
26     while (continue) {
27       receive {
28         case (id: Int, direction: Int) =>
29           sendMessage(id: Int, direction: Int)
30         case "finish" =>
31           continue = false
32           val endTime = System.nanoTime
33           println("Finish, spend time:" +
34             (endTime - startTime) / 1000000000.0 + " secs")
35         case _ => println("input error")
36       }
37     }
38   }
39 
40   def reactMessage {
41     var continue = true
42     loopWhile(continue) {
43       react {
44         case (id: Int, direction: Int) =>
45           sendMessage(id: Int, direction: Int)
46         case "finish" =>
47           continue = false
48           val endTime = System.nanoTime
49           println("Finish, spend time:" +
50             (endTime - startTime) / 1000000000.0 + " secs")
51         case _ => println("input error")
52       }
53     }
54   }
55 
56   //direction=0->sendLatter;direction=1->sendFormer
57   def sendMessage(id: Int, direction: Int) {
58     if (direction == 0 && id != length) {
59       info("Actor" + id + " send message to the Actor" + (id + 1))
60       actors.get(id + 1! (id + 10)
61     } else if (id != 0 && direction == 1) {
62       info("Actor" + id + " send message to the Actor" + (id - 1))
63       actors.get(id - 1! (id - 11)
64     } else if (direction == 0 && id == length) {
65       actors.get(length) ! (length, 1)
66     } else if (id == 0 && direction == 1) {
67       actors.get(0! "finish"
68     }
69   }
70 }
复制代码

 

       前些天看到Scala正在努力支持.net平台,不过我觉得.net平台有F#,所以对于.net程序员来说Scala提供不了什么

附加价值。如果非要找出来这样做的优点的话,就是Scala可以同时支持两个主流平台,野心不小。如果看后有所收获,请

推荐让更多人看到,算我为Scala的推广尽了点绵薄之力。行文仓促,如果有不对的地方,欢迎指正。

分享到:
评论

相关推荐

    在浏览器上运行 Scala Scala.js.zip

    通过学习和实践,开发者不仅可以利用Scala.js开发高性能的前端应用,还可以享受到类型安全和静态分析带来的好处,降低出错率,提高代码质量。此外,全栈Scala开发也能提高团队间的沟通效率,因为前后端代码共享相同...

    响应式架构 消息模式Actor实现与Scala.Akka应用集成 高清扫描版

    响应式架构 消息模式Actor实现与Scala.Akka应用集成 高清扫描版

    响应式架构 消息模式Actor实现与Scala.Akka应用集成

    响应式架构是一种设计模式,...而提供的"响应式架构 消息模式Actor实现与Scala.Akka应用集成"文档,很可能是对这些概念的详细讲解,包括沃恩·弗农的观点和实践经验,对于深入理解Akka和响应式架构有着重要的参考价值。

    scala-js-ts-importer, Scala.js的打印机导入程序.zip

    scala-js-ts-importer, Scala.js的打印机导入程序 从打字类型定义到 Scala.js的导入程序这里工具读取为 TypeScript 编写的类型定义文件,并将它们重写为可以使用 Scala.js的. scala 文件。过程不精确 100 %,因此...

    响应式架构++消息模式Actor实现与Scala.Akka应用集成+,沃恩·弗农+

    在《响应式架构++消息模式Actor实现与Scala.Akka应用集成+》中,作者沃恩·弗农深入探讨了如何利用Akka和Scala来构建响应式的应用程序。他可能详细讲解了以下知识点: 1. **Actor系统**:介绍Akka中的Actor系统是...

    Scala.uew UltraEdit关于Scala的wordfiles

    这个是UltraEdit编辑器中的关于Scala的高亮文件类型。

    大数据技术之Scala.docx

    4. Scala在设计时,马丁·奥德斯基是参考了Java的设计思想,可以说Scala是源于Java,同时马丁·奥德斯基也加入了自己的思想,将函数式编程语言的特点融合到JAVA中。 Scala的应用领域非常广泛,包括大数据处理、...

    响应式架构 消息模式Actor实现与Scala.Akka应用集成 ,沃恩·弗农

    响应式架构是一种设计思想,它强调系统在面对不断变化的工作负载和网络延迟时,能够保持弹性、反应迅速...阅读"响应式架构 消息模式Actor实现与Scala.Akka应用集成"这本书,将有助于你掌握这些概念并应用于实际项目中。

    Programming.in.Scala.pdf

    《Programming in Scala.pdf》是一本专注于Scala编程语言的书籍。Scala是一种现代的多范式编程语言,专为可扩展性而设计。该书旨在为读者提供深入理解Scala语言的教程。 ### 描述 描述中提及的内容表明,...

    Artima.Actors.in.Scala.Mar.2011

    《Scala中的Actor模型》是一本由Philipp Haller和Frank Sommers合著的专业书籍,该书详细介绍了Scala语言中Actor模型的基础理论与实际应用。Philipp Haller不仅是本书的作者之一,同时也是Scala Actor框架的主要创造...

    scala-2.12.14.zip&scala-2.12.11.tgz Linux版本压缩包.rar

    Spark使用Scala的Actor模型来实现并发,这使得Spark可以在多核系统或分布式集群上高效运行。 Scala的特性包括: 1. **类型推断**:开发者无需为每条语句都指定类型,编译器可以根据上下文自动推断。 2. **模式匹配*...

    移植到 Scala.js 的 简单HTML5 Canvas游戏_Scala_代码_下载

    1. **Scala.js**: Scala.js是Scala编程语言的一个编译器插件,它允许开发者使用Scala语法编写前端代码,并将其编译成可执行的JavaScript代码。这使得开发者可以利用Scala的强大特性和类型系统来开发Web应用,同时...

    akka-js, Scala.js的Akka actor实现.zip

    akka-js, Scala.js的Akka actor实现 但是,这个项目不被维护,另外一个项目 !目前并没有积极地开展这个项目。 在这里提供一个主动维护的到 Scala.js的端口,可以: https://github.com/unicredit/akka.js 。我们...

    Actors in Scala.pdf

    它不仅详细介绍了Scala语言中Actor模型的实现与应用,还深入探讨了多核时代下并发编程的理论与实践,为开发者提供了一套全面的并发编程指南。无论是初学者还是经验丰富的开发者,都能从中获得宝贵的启示和知识。

    响应式架构 消息模式Actor实现与Scala.Akka应用集成.rar

    其中包括:Actor模型和响应式软件的主要概念、Scala语言的基础知识、Akka框架与Akka集群功能、Actor模型中的通道机制和技术、降低消息源与消息目的地之间耦合性的方式、持久化Actor对象和幂等接收者。附录A中还介绍...

    scala.rar学习笔记和心得

    Scala 是一门多范式(multi-paradigm)的编程语言,设计初衷是要集成面向对象编程和函数式编程的各种特性。 Scala 运行在Java虚拟机上,并兼容现有的Java程序。 Scala 源代码被编译成Java字节码,所以它可以运行于...

Global site tag (gtag.js) - Google Analytics