Actor里的偏函数与性能

Evan Chan分享的《Akka in Production: Our Story》是一篇非常务实的工程实践分享,里面有很多可借鉴的点子,其中的一个对消息接受的包装逻辑主要预留了扩展点:

trait ActorStack extends Actor {

    def wrappedReceive: Receive // Receive类型是一个偏函数

    def receive: Receive = {
        case x => if (wrappedReceive.isDefinedAt(x)) wrappedReceive(x) else unhandled(x)
    }
}

大部分人在实现业务逻辑时可能如下

class MyActor extends ActorStack {

    def wrappedReceive: Receive = {
        case Something => balabala
    }
}

这种情况下会有个小小的性能浪费,每次接收消息的时候,至少要创建一次偏函数对象。如果消息又正好在wrappedReceive里定义了的话,创建了2次偏函数对象,因为调用了2次wrappedReceive方法;这个是可以避免的,用一个成员把这个偏函数对象保存起来,避免每次都创建:

trait ActorStack extends Actor {

    def wrappedReceive: Receive

    private val logic = wrappedReceive

    def receive: Receive = {
        case x => if (logic.isDefinedAt(x)) logic(x) else unhandled(x)
    }
}

或许看客们又好奇,那么Akka对receive这个函数返回的偏函数又是怎么处理的?是否也存在每次都生产一下(同样的性能浪费),还是保存在某个地方? 没错,它在底层实现里是被放到behaviorStack这个行为栈里的,每次处理逻辑的时候从行为栈里取出这个偏函数进行调用。

Actor里的偏函数与性能》上有4个想法

    • 没有测过,应该是微乎其微的,但能减少对象的无谓创建也是一种美德;-)

  1. 请教博主,scala的map方法,传入单个偏函数会报错,但是如果两个偏函数 orElse后,可以传给map方法,并且可以正常运行。看了下orElse后返回类型仍是偏函数,此时map为什么就可以了呢?
    val isEven:PartialFunction[Int,String]={
    case x if x%2==0=>x+” is even”
    }
    val isOdd:PartialFunction[Int,String]={
    case x if x%2==1 =>x+” is odd”
    }
    val sample =1 to 5
    sample.map(isOdd )//报错
    sample.map(isOdd orElse isEven)//正常

发表评论

电子邮件地址不会被公开。 必填项已用*标注