Actors in Scala(Scala中的Actor)(预打印版) 第四章 Actor Chat (B)

Actors in Scala(Scala中的Actor)(预打印版) 第四章 Actor Chat (B)

张贵宾

guibin.beijing@gmail.com


2011.10.24

注:翻译这些英文书籍资料纯属个人爱好,如有不恰当之处敬请指正。


4.3 Sending actor messages

到目前为止,ChatRoom已经一切就绪,可以处理订阅的消息了。Scala的actor库同时支持同步和异步消息传输。

异步发送消息

给一个actor异步发送一条消息使用 ! 方法。Scala遵从了Erlang语言中actor的传统,使用惊叹号 ! 代表消息发送。
val chatRoom = new ChatRoom
chatRoom ! Subscribe(User("Bob"))
var session = Map.empty[User, Actor]
while(true) {
  receive {
    case Subscribe(user) =>
      val sessionUser = 
        actor {
          while(true) {
            self.receive {
              case Post(msg) => //把消息发送给sender
            }
          }
        }
    session = session + (user -> sessionUser)
    //Handle the Unsubscribe message
  }
}


使用惊叹号 ! 给chatRoom发送消息并且会立即返回:此方法不会等待目标actor的确认或者回复。发送消息后,消息接收的actor除了能收到消息之外,它还能接收到一个的对发送消息actor的隐式引用sender。这个引用(用变量sender表示)在目标actor(就是接收消息的actor)内始终是可用的。下面的代码展示了目标actor如何使用sender变量引用去处理一条Post消息的:
val chatRoom = new ChatRoom
chatRoom ! Subscribe(User("Bob"))
var session = Map.empty[User, Actor]
while(true) {
  receive {
    case Subscribe(user) =>
      val subscribe = sender
      val sessionUser = 
        actor {
          while(true) {
            self.receive {
              case Post(msg) => subscribe ! Post(msg)
            }
          }
        }
    session = session + (user -> sessionUser)
    //Handle the Unsubscribe message
  }
}

注意,在上面的例子中有两个actor,一个是ChatRoom,另一个是代表聊天室中的用户sessionUser。当聊天室actor收到Subscribe消息后,它把这条消息的发送者的引用赋值给subscriber变量,这个传递给actor方法的闭包,反过来捕获了sender变量,使得subscriberActor接收和处理Post消息成为可能。一旦sessionUser初始化成代表订阅消息的用户后,它就被存在了session map中。

同步发送消息

Scala同时也支持使用 !? 操作符发送同步消息,
val chatRoom = new ChatRoom
chatRoom !? Subscribe(User("Bob"))

不像异步发送消息,!? 操作会阻塞调用线程,直到消息被发送出去并且收到响应为止。下面的代码展示了ChatRoom当处理一个带有reply方法的订阅消息时返回一个确认消息的情况。
客户端可以捕获并处理这个响应:

chatRoom !? Subscribe(User("Bob")) match {
  case response: String => println(response)
  }
  var session = Map.empty[User, Actor]
  while(true) {
    receive {
      case Subscribe(user) =>
        val subscriber = sender
        val sessionUser = 
        actor{
          while(true) {
           self.receive {
             case Post(msg) => subscriber ! Post(msg)
           }
          }
        }
    }
    session = session + (user -> sessionUser)
    reply("Subscribed " + user)
  }
}

Futures

在某些情况下,你希望发送消息之后,调用的线程立即返回,但是你又在之后的某个时刻想要访问目标actor的返回结果。比如,你想在发送完订阅消息之后很快的返回,但是之后记录聊天室的返回信息。Scala actor为这样的场景也提供了future。Future消息使用双惊叹号 !! 方法发送,这个方法返回一个Future而不阻塞调用的线程。Future的值可能被调用者评估,也可能不被调用者评估,如果调用者评估Future,但在评估时future的值尚未返回,那么此时将会阻塞评估的线程。如下代码所示:

val future = chatRoom !! Subscribe(User("Bob"))//此调用不阻塞
//做一些有用的工作
println(future())//此调用将阻塞,直到future()返回结果

Message timeouts(消息超时)

在目前的例子中,receive会阻塞actor的主线程,直到收到一条能匹配上的消息为止。在某些情况下,你想在合理的时间里等到需要的消息。那么receiveWithin方法就允许你指定消息超时时间,如果在指定的时间内消息没有到达,则会有超时提示给你。

你可以使用receiveWithin方法自动取消用户的订阅消息,如果用户在指定的时间段内没有收到任何Post消息。在下面的例子中,如果在3分钟之内没有匹配到Post消息,那么TIMEOUT将会被匹配到,接着用户就会被取消与聊天室的订阅关系。

val sessionUser = actor {
  while(true) {
    receiveWithin(1800 * 1000) {
      case Post(msg) => subscriber ! Post(msg)
      case TIMEOUT => 
        room ! Unsubscribe(user)
        self.exit
    }
  }
}

Processing user posts(处理用户发帖)

实现我们聊天室所有功能所剩下的就是处理用户的发帖。代码如下:

var session = Map.empty[User, Actor]
def act() {
  while(true) {
    receive {
      case PostFrom(user, msg) =>
        for(key <- session.keys; if key != user) {
          session(key) ! msg
        }
    }
//Handle the Subscribe message
//Handle the Unsubscribe message
  }
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值