我正在为C#桌面应用程序(不是服务器,而是桌面GUI应用程序)编写插件。 为了简化线程问题,我正在研究是否可以在这些插件中使用AKKA.NET。 插件原则上是相互独立的。 因此,从体系结构POV中,很自然地为每个插件提供其自己的“私有” ActorSystem实例。 这种方法的优点是插件之间最大程度地隔离。 另一方面,我阅读了一些有关JVM的Akka的文章,这些文章告诉我,在应用程序中有太多ActorSystem实例是一种反模式,因为ActorSystem的重量很重。
实际的并发插件数量为10-20,即该应用程序可能在内部运行20个ActorSystem实例。同样,这是一个GUI桌面应用程序,通常在终端服务器会话中运行(即,终端服务器上可能运行着许多此类GUI应用程序)。
那么-这种简单的方法(每个库一个ActorSystem)是否可行?或者使用全局ActorSystem设计一种方法更好,该方法使用每个插件的顶级actor来隔离插件。 这种方法可能会提高性能,但是我对此有点担心,因为这些插件之间的隔离程度不高。
那么-这种“多系统”方法是一种好的架构方法,还是坚持“一个全局系统”的设计更好?您在这里有什么经验?
答案 0 :(得分:4)
那么-这种简单的方法(每个库一个ActorSystem)是否可行?或者使用全局ActorSystem设计一种方法更好,该方法使用每个插件的顶级actor来隔离插件。这种方法可能会提高性能,但是我对此有点担心,因为这些插件之间的隔离程度不高。
这是我要使用的方法-让每个插件使用相同的ActorSystem
创建自己的参与者层次。每个插件可以有自己的参与者和消息类型,并且没有重叠。如果最终运行了多个ActorSystem
,则最终仍然会有多个参与者都使用相同的线程,因为默认情况下,ActorSystem
将参与者调度到TPL和其他线程所在的.NET线程池中您的桌面应用程序的某些部分可能会使用。用一个ActorSystem
来管理所有这一切可能是最容易的,因为那样的话,您只有一个调度程序来在同一组线程中编组执行(竞争较少)。
答案 1 :(得分:2)
如果隔离是您的目标,那么多个参与者系统将无法解决您的问题-ActorSystem
只是一个普通的类,您仍然可以使用静态字段共享数据,并且(可能)您仍然可以访问如果有足够的决心,请使用其他角色系统。因此,如果您运行不受信任的代码,actor系统将无法为您提供帮助。
可以通过在旧.NET Framework中使用AppDomains或.NET Core中的AssemblyLoadContext来实现.NET中真正的进程内隔离。
请记住,使用actor编程范例是认真的设计决策,并且可以通过多种方式实现组件隔离。因此,如果组件隔离是唯一的原因,那么您决定使用actor的原因可能就是要找出并重新考虑其他选项。
您可以为每个插件使用actor,甚至可以使用本机Akka.NET扩展-这种机制使我们能够为akka本身构建插件。 Akka几乎所有更高级别的功能都作为扩展而构建:集群,远程处理,集群分片,持久性等。
要构建扩展,您需要两个类:
public class MyExtensionProvider : ExtensionIdProvider<MyExtension>
{
public override MyExtension CreateExtension(ExtendedActorSystem system) =>
new MyExtension(system);
}
public class MyExtension : IExtension
{
public MyExtension(ExtendedActorSystem system) { }
}
您可以通过以下代码从代码本身注册和检索那些扩展:actorSystem.WithExtension<MyExtension, MyExtensionProvider>()
(该方法的签出替代)。您也可以直接在HOCON中注册它们-这样,当通过HOCON config提供它们时,它们将在系统启动时自动启动:
akka.extensions = [
"MyNamespace.MyExtensionProvider1, MyAssembly",
"MyNamespace.MyExtensionProvider2, MyAssembly"
]