Multithreading 阿克卡:如何确保信息已被接收?

Multithreading 阿克卡:如何确保信息已被接收?,multithreading,scala,akka,actor,Multithreading,Scala,Akka,Actor,我有一个演员配药器。它的作用是什么 按要求分发一些物品 听新的 代码如下 class Dispenser extends Actor { override def receive: Receive = { case Get => context.sender ! getObj() case x: SomeType => addObj(x) } } 在实际处理中,从新对象发送到分发器开始分

我有一个演员配药器。它的作用是什么

  • 按要求分发一些物品
  • 听新的
  • 代码如下

    class Dispenser extends Actor {
        override def receive: Receive = {
            case Get =>
                context.sender ! getObj()
            case x: SomeType =>
                addObj(x)
        }
    }
    
    在实际处理中,从新对象发送到分发器开始分发之前,1毫秒甚至几秒钟的时间都无关紧要,因此没有代码跟踪它

    但现在我正在为分配器编写测试,我想确保它首先接收新对象,然后才接收Get请求

    下面是我提出的测试代码:

    val dispenser = system.actorOf(Props.create(classOf[Dispenser]))
    dispenser ! obj
    Thread.sleep(100)
    val task = dispenser ? Get()
    val result = Await.result(task, timeout)
    check(result)
    
    它满足了一个重要的要求—它不改变原始代码。但事实确实如此

  • 即使在高性能的机箱上,速度也至少慢100毫秒
  • 不稳定,有时会失败,因为100ms或任何其他常数不能提供任何保证
    问题是如何做一个满足要求且没有上述缺点的测试(也没有任何明显的缺点)

    你可以去掉
    线程。睡眠(…)
    ,你的测试就可以了。Akka保证您所需的订单

    使用代码

    dispenser ! obj
    val task = dispenser ? Get()
    
    分配器
    将在
    Get
    之前处理
    obj
    ,因为

  • 同一个线程将
    obj
    然后
    Get
    放入参与者邮箱,因此它们在参与者邮箱中的顺序正确
  • 参与者按顺序一次处理一条消息,因此参与者将接收这两条消息,并按照它们在邮箱中排队的顺序进行处理

  • (…如果示例代码中没有其他内容-路由器,getObj或addObj中的异步处理,隐藏,…)

    Akka FSM模块对于测试参与者的底层状态和行为非常方便,并且不需要专门为测试更改其实现。 通过使用TestFSMRef,可以通过以下方式获取参与者的当前状态和数据:

    val testActor = TestFSMRef(<actors constructor or Props>)
    testActor.stateName shouldBe <state name>
    testActor.stateData shouldBe <state data>
    

    val testActor=TestFSMRef(

    您可能必须使测试参数化:将睡眠时间更改为1毫秒,并运行一整段时间。如果工作时间>92%,测试通过。92%是我不知道的数字。选择您的数字并对其满意。我不认为这会扼杀部署过程(包括自动测试运行)8%(甚至0.01%)案例分析是进行测试的正确方法。因此,我更喜欢不涉及统计的解决方案。在akka的第一个版本中,有一个基于邮箱大小的解决方案。对于akka2,此功能已被禁用。但是邮箱仍然可以在您自己的系统中实现。但是否存在更简单、更直观的解决方案?您阅读了吗?@Daenyth感谢您的链接。我对类似于ask模式的解决方案持开放态度,在成功交付的情况下,一切都会正常工作,在其他情况下,它等待的时间不会超过给定的超时时间。这不是真的。订购保证仅适用于以fire and forget方式发送的邮件。使用ask模式时,邮件会避开邮箱,直接发送到to目的地,因此无法保证obj和Get()顺序。请求
    .ask()
    只是一个
    .tell()
    -签出。首先,原因是:
    ask
    操作涉及创建一个内部参与者。其次,它确实发生了(甚至更经常发生)顺序实际上发生了变化。内部参与者将接收响应-请求通过调用线程中的
    .tell
    。您是否查看了
    AskSupport
    源代码?如果您使用的是akka testkit,您可以使用tell Obj、tell Get和expectMsg。这将保证消息顺序。