跟连乐一起学Scala-Actor

  1. 每个actor都要扩展Actor类并提供act方法;
  2. 要网actor发送消息,可以使用actor ! message
  3. 消息发送时异步的,“发完就忘”
  4. 要接收消息,actor可以调用receive或react,通常是在循环中这样做
  5. receive/react 的参数是由case语句组成的代码块
  6. 不同的actor之间不应该共享状态。总是使用消息来发送数据。
  7. 不要直接调用actor的方法。通过消息进行通信。
  8. 避免同步消息–也就是说将发送消息和等待响应分开。
  9. 不同actor可以通过react而不是receive来共享线程,前提是消息处理器的控制流转足够简单。
  10. 让actor挂掉是OK的,前提是你有其他actor监控着actor的生死。用链接来设置监控关系。

创建和启动Actor

import scala.actor.Actor

class HiActor extends Actor {
    def act (){
        while (true) {
            receive {
                case "Hi" => println("Hello")

            }
        }
    }
}
val actor1 = new HiActor
actor1.start()

如果需要临时创建一个actor而不是定义一个类,Actor伴生对象带有一个actor方法来创建和启动actor:

import scala.actors.Actor._

val actor2 = actor {
    whhile(true) {
        receive {
        case "Hi" => print("hello)
        }
    }
}


发送消息

使用actor定义的!操作符。

actor1 ! "Hi"


接收消息

使用case接收对象。


向其他Actor发送消息

当运算被分拆到不同actor来并行处理问题的各个部分时,这些处理结果需要被收集到一起。

设计选择如下:

1. 可以有一个全局的actor。

2. actor可以构造成带有指向一个或更多actor的引用。

3. actor可以接收带有指向另一个actor的引用的消息。在请求中提供一个actor引用是常见的做法,比如:actor ! Compute(data, continuation)

4. actor可以返回消息给发送方。receive方法会把sender字段设为当前消息的发送发。



消息通道

消息通道是类型安全的–你只能接受或发送某个特定类型的消息。

你不会不小心通过消息通道调用某个actor的方法。

消息通道可以是一个OutputChannel(带有!方法),也可以是一个InputChannel(带有receive或react方法)。Channel类同时扩展OutputChannel和InputChannel特质。

val chnnel = new Channel [Int] (someActor)
case class Compute(input: Seq[Int], result: OutputChannel[Int])

class Conputer extends Actor {
    public void act (){
        while (true){
            receive {
                case Compute(input, out) => (val answer = ...; out ! answer)
            }
        }
    }
}

actor {
    val channel = new Channel[Int]
    val computeActor: Computer = ...
    val input: Seq[Double] = ...
    computeActor ! Compute(input, channel)
    channel.receive {
        case x => ...//我们已知x是一个int
    }

}


同步消息和Future

actor可以发送一个消息并等待回复,用!?操作符:

val reply = account !? Deposit(1000)
reply match {
    case Balance(bal) => println("Current Balance: " + bal)
}

接收方必须返回一个消息给发送方:

receive {
    case Deposit(amount) => {balance += amount; sender ! Balance(balance)}
}

可以使用receiveWithin方法指定你想要等待多少时间:

actor {
    worker ! Task(data, self)
    receiveWithin(seconds * 1000) {
        case Result (data) => ...
        case TimeOUT => log(...)
    }
}

可以使用!!来接受一个future—这是一个将在结果可用时产生结果的对象。

val replayFuture = account !! Deposit(100)
val replay = replyFuture()
//这个调用将会阻塞,直到回复被发送。


Actor的生命周期

actor的act方法在actor的start方法被调用时开始执行。

def act {
    while(有更多事情要处理) {
        receive {
            ...
        }
    }
}

actor在如下情形之一会终止执行:

1. act方法返回。

2. act方法由于异常被终止。

3. actor调用exit方法。



将多个Actor链接在一起

def act () {
    link (master)
    ...
}

连接是双向的。



Actor的设计

一些建议:

  1. 避免使用共享状态。
  2. 不要调用actor的方法。
  3. 保持每个actor的简单。
  4. 将上下文数据包含在消息中。
  5. 最小化给发送方的回复。
  6. 最小化阻塞调用。
  7. 尽可能使用react.
  8. 建立失败区。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2025-01-16 13:24:13

跟连乐一起学Scala-Actor的相关文章

scala Actor -03

1.对于上一篇讲解的scala的一些补充 val files = Array[String]("a.txt","b.txt","c.txt") for(f <- files){xxxx} 目标一:熟悉Scala Actor并发编程 目标二:为学习Akka做准备 注:我们现在学的Scala Actor是scala 2.10.x版本及以前版本的Actor. Scala在2.11.x版本中将Akka加入其中,作为其默认的Actor, 老版本的Ac

跟连乐一起学Scala-集合

欢迎加入Scala讨论QQ群212859367,和连乐一起讨论学习! 集合 主要的集合特质 Seq 是一 个有先后次序的值的序列.比如数组和列表.IndexedSeq允许我们通过整型的下标快速的访问任意元素. Set 是一组没有先后次序的值.在SortedSet中,元素以某种排过序的顺序被访问. Map 是一组(键,值)对偶.SortedMap按照键的排序访问其中的实体. 序列 Vector是ArrayBuffer的不可变版本:一个带下标的序列,支持快速的随机访问. 向量是以树形结构的形式实现的

快学Scala 第十九课 (trait的abstract override使用)

trait的abstract override使用: 当我看到abstract override介绍的时候也是一脸懵逼,因为快学scala,只介绍了因为TimestampLogger中调用的super.log依旧是个abstract class,所以必须在方法前加上abstract和override.但是并没有具体介绍如何使用,然后查阅了其他文档,才明白使用方法. 下面的代码定义了超类LoggerEmpty,这个定义意味着该特质只能混入扩展LoggerEmpty的类中. 在特质中声明抽象方法中有

快学Scala课后习题答案

分享一个之前做快学Scala的课后习题(2-21章节,19无)的Github链接,我把习题的文字写在了每个回答的注释上面,这样方便大家对照着看,省的回过头去对照着pdf看了,如果有做的不对的地方希望大家给予指正. 链接如下,http://github.com/fxxkinglife/scala-hello. 举一个第二章节的例子, object charpter02 { /* * 2.1 * 一个数字如果为正数,则它的signum为1; * 如果是负数,则signum为-1; * 如果为0,则s

快学scala 第十一章 操作符 读书笔记及习题答案代码

chapter 11 操作符 标签:快学scala 一.笔记 scala种可以在反引号中包含几乎任何字符序列, val 'val' = 42 所有的操作符都是左结合的,除了以冒号(:)结尾的操作符,和赋值操作符.用于构造列表的::操作符是又结合的.1::2::Ni1的意思是1::(2::Ni1),先创建出包含2的列表,这个列表又被作为尾巴拼接到以1作为头部的列表中. 2. 函数调用语法:f(arg1, arg2,...)扩展到可以应用于函数之外的值,如果f不是函数或方法,那么这个表达式等于f.a

快学Scala习题解答—第一章 基础

1 简介 近期对Scala比较感兴趣,买了本<快学Scala>,感觉不错.比<Programming Scala:Tackle Multi-Core Complexity on the Java Virtual Machine>好很多. 是本不错的入门书.而且每个章节都设置了难度级别,每章有习题,可以巩固Scala语法. 本文的目的就是针对这些习题进行解答 2 基础 2.1 在Scala REPL中键入3,然后按Tab键.有哪些方法可以被应用? 这个....直接操作一遍就有结果了.

快学scala笔记.

第一章 基础 val 定义的值实际上是一个常量 var 声明其值可变的变量 val xmax,ymax = 100 var greeting,message: String = null 1.3 常用类型 Scala的7种数值类型:Byte.Char.Short.Int.Long.Float和Double 1.toString() 2.to(10) "Hello".intersect("World") 1.4 算术和操作符重载 val answer = 8 * 5

乐哥学AI_Python(二):Numpy索引,切片,常用函数

Numpy的索引和切片 ndarray对象的内容可以通过索引和切片查看和修改. 索引:ndarray对象中的元素索引基于0开始 切片:对数组里某个片段区域的描述 数组的切片也可以理解为原始数组的局部视图,都是指向内存中的原始数组,所以不同于列表复制,切片上的修改都会直接反映到原始数组上. 索引切片的实例代码演示: Numpy常用函数的代码演示: Numpy的置换函数transpose.T和swapaxes演示与区别 T适用于一.二维数组 arr = np.arange(12).reshape(3

跟连乐一起学Scala-类型参数

欢迎加入Scala讨论QQ群212859367,和连乐一起讨论学习! 泛型类 例子: class Pair[T, S](val first: T, val second: S) 泛型函数 例子: def getMiddle[T](a: Array[T] = a(a.length / 2)) Scala会从调用该方法使用的实际参数来推断出类型. getMiddle(Array("Mary", "had", "a", "little&quo