在实践中在何处以及如何使用行动者



如何在复杂的后端服务中使用actor,这些服务包括接收初始请求、进行一些处理,然后向其他服务发送一些请求/要做的事情,等待其中一些服务的响应,并根据响应决定如何继续,等等,直到我们计算出最终结果?

尝试使用参与者来实现此类服务会引发一个问题-此工作流的哪些部分应该由参与者来实现,哪些部分不应该由参与者实现

参与者实例在他们试图完成的任务完成之前不会释放他们正在使用的线程(除非我们将其委托给Future),所以在我看来,将整个工作流写成一个由越来越小的参与者组成的层次结构,其中有N层子层,一方面是基于参与者概念的理想设计,但另一方面,它将保持多达N-1个线程(每个初始请求)——不断锁定,只等待层次结构中最底层的参与者之一完成。具体来说,层次结构中最顶层的参与者在大部分时间都处于空闲状态。

这种分层设计也与错误内核模式相匹配。

但这听起来对并发性非常不利。

即使你试图保持演员的层次结构,但将对每个演员的调用封装在一个"未来"中(通过询问儿童演员,而不是告知),所以锁定时间会短得多(尽管它仍然存在)-仍然与这么多"未来"一起工作,使得不可能与有状态的演员一起工作,或者以自己不同步的方式修改系统状态的参与者(即,不是简单地修改数据库,至少对于简单的请求,这是通过数据库事务自动完成的,而是修改应用程序中的一些全局变量)。

那么,参与者是否应该只用于工作流的较低级别?

或者,应该以更串行的方式重写一个主要是分层的(大多数都是分层的)工作流,这样它就不需要那么多级别的子参与者(但这会非常困难和不自然,而且似乎会给实现框架带来太多对设计的影响)。

这意味着您认识到参与者是非常有限的,容错应该主要由传统的异常处理来处理,并且在任何情况下,拥有容错应用程序的愿望都不应该对应用程序的设计产生太大影响。既然如此,为什么还要麻烦演员呢?使用一个需要阅读每个参与者的实现才能理解复杂的意大利面条式消息结的工作流程的框架,要比使用基于层次结构的框架容易得多,层次结构可以通过查看方法签名在任何期望的程度上显示出来,而不必查看它们的实现。

如果应用程序的一小部分是由参与者实现的,那么参与者的许多好处(如易于扩展)似乎不那么相关或实用。

我认为您对actors中"锁定"的理解是错误的。

你写

,但另一方面,它将保持多达N-1个线程(每个初始请求)-持续锁定,无所事事

不清楚您在这里描述的是哪种情况。正在使用的线程数不是由参与者层次结构中的参与者或层的数量决定的,而是由运行参与者的调度器决定的,请参阅https://doc.akka.io/docs/akka/2.5/dispatchers.html?language=scala

参与者通常不会生成新线程,也不会在空闲时阻塞任何东西。它将处理(可配置的)数量的消息,然后将控制权交还给调度器。因此,就多线程而言,与你所怀疑的相反,Akka是非常高效的。

如果您试图保留此参与者层次结构,但将调用包装为未来中的每个演员(通过询问儿童演员,而不是告诉),所以锁定会短得多

那里一定有误解。向另一个参与者发送消息的参与者不会阻塞线程。目前还不清楚你指的是什么"锁定"。此外,ask使锁定更短的假设显然是有缺陷的,因为没有锁定。

也许你担心的是使用阻止演员使用IO?这确实会阻塞正在执行的线程。这里的"诀窍"是将阻塞呼叫放在一个单独的调度器上,请参阅https://doc.akka.io/docs/akka/snapshot/dispatchers.html?language=scala

最新更新