普通的编程实践不能满足现代系统的苛刻要求。幸运的是,我们不需要丢弃我们所知道的一切。相反,行动者模型解决了现有方式中的这些缺点,使系统的行为更符合我们的心理模型。
使用演员模型,我们可以:
*在不使用锁的情况下实施封装。
*使用实体模型响应信号,改变状态,相互发送信号,从而推动整个应用向前发展。
*不要担心实现机制与我们的世界观不一致。
#使用消息传递避免锁定和阻塞
参与者不需要调用方法,而是互相发送消息。Actor可以发送消息并继续处理其他任务,而不会阻塞。因此,它可以在同一时间做更多的工作。
当对象和方法返回时,其执行线程的控制被释放。在这方面,actor的行为很像对象,它们对消息做出反应,并在处理当前消息后返回。通过这种方式,actor实际上实现了我们为对象设想的执行:
传递消息和调用方法的重要区别在于消息没有返回值。通过发送消息,演员将作品委托给另一个演员。正如我们在调用堆栈中看到的,如果返回值是预期的,发送方参与者需要阻止或执行同一线程上其他参与者的工作。
我们需要在模型中进行的第二个关键更改是恢复封装。参与者对消息做出反应,就像对象对调用它们的方法做出“反应”一样。不同的是,actor一次只响应一个传入的消息。当每个参与者按顺序处理发送给它的消息时,不同的参与者将同时并发工作,这样系统就可以同时处理尽可能多的硬件支持的消息。
由于每个参与者最多只能处理一条消息,因此无需同步和锁定即可保持参与者的不变性:
综上所述,当actor收到消息时,会发生以下情况:
1.actor将消息添加到队列的末尾。
2.如果执行者没有被安排执行,将其标记为准备执行。
3.(隐藏的)调度程序实体接受参与者并开始执行它。
4.actor从队列的前面选择消息。
5.actor修改内部状态并将消息发送给其他actor。
6.演员的计划外任务。
为了完成这一行为,参与者必须:
*邮箱(邮件结束的队列)。
*行为(行动者的状态、内部变量等。).
* message(表示信号的数据片段,类似于方法调用及其参数)。
*执行环境(消息参与者响应和调用其消息处理代码的机制)。
*地址。
消息进入参与者的邮箱,参与者的行为描述了参与者如何响应消息(例如发送更多消息和/或更改状态)。执行环境安排了一个线程池来完全透明地驱动所有这些操作。
这是一个非常简单的模型,它解决了上面列出的问题:
*通过将执行与消息分开来保持封装。
*不需要锁定,只能通过消息修改actor的内部状态。
*任何地方都不用锁,在十几个线程上可以有效调节百万个actor,充分发挥了现代CPU的潜力。
*参与者的状态是本地的,不是共享的,更改和数据通过消息传输。在电信中,状态保存在机器的随机存取存储器中,变化/数据作为数据包在网络上传播。
# actor可以很好地处理错误情况。
由于我们不再有一个共享的调用堆栈来相互发送消息,我们需要以不同的方式处理错误情况。我们只需要考虑两种错误:
*第一种情况是,由于任务中的错误(通常是一些身份验证问题,例如不存在的用户ID),目标参与者上的委托任务失败。在这种情况下,由目标参与者封装的服务是完整的。服务参与者应该向发送者回复一条指示错误情况的消息。这里没什么特别的。错误是系统的一部分,所以它们是普通的消息。
*第二种情况是服务本身遇到内部故障。Akka强制将所有演员组织成一个树形层次结构,即创建另一个演员的演员成为新演员的父代。这与操作系统将进程组织成树的方式非常相似。就像一个过程,当一个参与者失败时,它的父参与者可以决定如何应对失败。同样,如果父角色停止,其所有子角色将递归停止。这种服务叫监督,是Akka的核心。
演员模型