Akka.DI.Autofac 没有创建演员
Akka.DI.Autofac did not create actor
我正在尝试设置 DI,然后是官方 akka.net 文档 (http://getakka.net/docs/Dependency%20injection#autofac)。然而,演员从不创造。以下我的代码有什么问题?
public class Worker: ReceiveActor
{
public Worker()
{
Receive<string>(m => Console.WriteLine("Worker is working"));
}
}
public class WorkerManager : ReceiveActor
{
public WorkerManager()
{
Receive<string>(m => Console.WriteLine("Manager start supervise"));
}
protected override void PreStart()
{
Context.ActorOf(Context.DI().Props<Worker>(), "Worker1");
}
}
class Program
{
static void Main(string[] args)
{
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterType<Worker>();
builder.RegisterType<WorkerManager>();
var system = ActorSystem.Create("DiTestSystem");
IContainer container = builder.Build();
IDependencyResolver resolver = new AutoFacDependencyResolver(container, system);
var manageRef = system.ActorOf(system.DI().Props<WorkerManager>(), "Manager1");
manageRef.Tell("Hello");
system.ActorSelection("/user/Manager1/Worker1").Tell("Hello");
Console.ReadLine();
}
}
当运行代码时,我得到了这个
[INFO][24/04/2017 1:50:11 AM][线程 0006][akka://DiTestSystem/user/Manager1/Worker1] 从 akka://DiTestSystem/deadLetters 到 akka:/ /DiTestSystem/user/Manager1/Worker1 未送达。遇到 1 个死信。
经理开始监督
我发现使用 Autofac 无法足够快地创建 Actor。
当我添加 Thread.Sleep(20) 时,最后,正确创建 actor。
static void Main(string[] args)
{
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterType<WorkerManager>();
builder.RegisterType<Worker>();
var system = ActorSystem.Create("DiTestSystem");
IContainer container = builder.Build();
IDependencyResolver resolver = new AutoFacDependencyResolver(container, system);
var manageRef = system.ActorOf(system.DI().Props<WorkerManager>(), "Manager1");
Thread.Sleep(20); // ADDED THIS LINE
manageRef.Tell("Hello");
system.ActorSelection("/user/Manager1/Worker1").Tell("Hello");
Console.ReadLine();
}
我认为这是一个很大的问题,因为这种方法不能保证演员在睡眠时间总是create/resolve。
我一直打开这个问题,因为我认为这不是一个正确的答案。
这里的问题是竞争条件。无论您是否使用 DI 容器创建 actor,都可能发生这种情况。
在使用 actor 系统时,您需要记住一切都是异步发生的。在将消息发送给 WorkerManager
参与者后,您的代码可以继续,但这并不意味着该消息实际上已被接收和处理。它实际上被发布到一个邮箱,供演员准备好后在不同的线程上处理。
最好不要尝试直接访问 Worker
演员,因为您有一个 WorkerManager
演员。就像在现实生活中,你通常会要求经理安排一些工作来完成,然后经理会依次决定需要哪些工人,并将必要的工作分配给他们。
Akka.NET 有一个 router feature 对这种情况很有用。我已经用一些额外的日志记录和路由器配置更新了您的示例代码。
void Main()
{
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterType<Worker>();
builder.RegisterType<WorkerManager>();
var container = builder.Build();
var system = ActorSystem.Create("DITestSystem");
var resolver = new AutoFacDependencyResolver(container, system);
var manager = system.ActorOf(system.DI().Props<WorkerManager>(), "Manager");
Console.WriteLine("Program: Created Manager");
for (int i = 0; i < 10; i++)
{
manager.Tell("Hello");
}
Console.ReadKey(true);
}
public class Worker : ReceiveActor
{
public Worker()
{
Receive<string>(m => Console.WriteLine($"Worker {Context.Self.Path.Name} received: {m}"));
}
protected override void PreStart()
{
Console.WriteLine($"PreStart: {Context.Self.Path}");
}
}
public class WorkerManager : ReceiveActor
{
IActorRef worker;
public WorkerManager()
{
Receive<string>(m =>
{
Console.WriteLine($"Manager received: {m}");
worker.Tell(m);
});
}
protected override void PreStart()
{
Console.WriteLine($"PreStart: {Context.Self.Path}");
var props = Context.DI().Props<Worker>().WithRouter(new RoundRobinPool(5));
worker = Context.ActorOf(props, "Worker");
}
}
注意 WorkerManager
演员中的这一行,它为 Worker
演员配置路由器。
var props = Context.DI().Props<Worker>().WithRouter(new RoundRobinPool(5));
这将导致 ManagerActor
以循环方式将消息转发给 5 个子 Worker
参与者。消息路由已为您处理,因此无需直接与 Worker
参与者交互。
该示例现在还会在获得对 ManagerActor
的引用后立即向 ManagerActor
发送 10 条消息。
for (int i = 0; i < 10; i++)
{
manageRef.Tell("Hello");
}
随着播放中的更多消息和一些日志记录,您可以看到事物的顺序不是确定性的。这是 运行.
的输出
Program: Created Manager
PreStart: akka://DITestSystem/user/Manager
Manager received: Hello
Manager received: Hello
Manager received: Hello
Manager received: Hello
Manager received: Hello
Manager received: Hello
Manager received: Hello
Manager received: Hello
Manager received: Hello
Manager received: Hello
PreStart: akka://DITestSystem/user/Manager/Worker/$b
PreStart: akka://DITestSystem/user/Manager/Worker/$d
PreStart: akka://DITestSystem/user/Manager/Worker/$f
Worker $b received: Hello
Worker $b received: Hello
Worker $f received: Hello
Worker $f received: Hello
PreStart: akka://DITestSystem/user/Manager/Worker/$c
Worker $c received: Hello
Worker $c received: Hello
PreStart: akka://DITestSystem/user/Manager/Worker/$e
Worker $d received: Hello
Worker $d received: Hello
Worker $e received: Hello
Worker $e received: Hello
这是另一个的输出。
Program: Created Manager
PreStart: akka://DITestSystem/user/Manager
PreStart: akka://DITestSystem/user/Manager/Worker/$b
PreStart: akka://DITestSystem/user/Manager/Worker/$c
PreStart: akka://DITestSystem/user/Manager/Worker/$d
PreStart: akka://DITestSystem/user/Manager/Worker/$f
PreStart: akka://DITestSystem/user/Manager/Worker/$e
Manager received: Hello
Manager received: Hello
Manager received: Hello
Manager received: Hello
Worker $d received: Hello
Worker $e received: Hello
Manager received: Hello
Manager received: Hello
Manager received: Hello
Manager received: Hello
Manager received: Hello
Worker $f received: Hello
Worker $e received: Hello
Manager received: Hello
Worker $f received: Hello
Worker $b received: Hello
Worker $b received: Hello
Worker $c received: Hello
Worker $c received: Hello
Worker $d received: Hello
您可以看到,在第一个 运行 中,WorkerManager
在创建任何子 Worker
actors 之前收到了所有消息。在第二个 运行 中,它在收到任何消息之前创建了所有子 Worker
actor。
要记住的要点是,最好通过消息进行交流,而不是对事情何时发生做出假设。
我正在尝试设置 DI,然后是官方 akka.net 文档 (http://getakka.net/docs/Dependency%20injection#autofac)。然而,演员从不创造。以下我的代码有什么问题?
public class Worker: ReceiveActor
{
public Worker()
{
Receive<string>(m => Console.WriteLine("Worker is working"));
}
}
public class WorkerManager : ReceiveActor
{
public WorkerManager()
{
Receive<string>(m => Console.WriteLine("Manager start supervise"));
}
protected override void PreStart()
{
Context.ActorOf(Context.DI().Props<Worker>(), "Worker1");
}
}
class Program
{
static void Main(string[] args)
{
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterType<Worker>();
builder.RegisterType<WorkerManager>();
var system = ActorSystem.Create("DiTestSystem");
IContainer container = builder.Build();
IDependencyResolver resolver = new AutoFacDependencyResolver(container, system);
var manageRef = system.ActorOf(system.DI().Props<WorkerManager>(), "Manager1");
manageRef.Tell("Hello");
system.ActorSelection("/user/Manager1/Worker1").Tell("Hello");
Console.ReadLine();
}
}
当运行代码时,我得到了这个
[INFO][24/04/2017 1:50:11 AM][线程 0006][akka://DiTestSystem/user/Manager1/Worker1] 从 akka://DiTestSystem/deadLetters 到 akka:/ /DiTestSystem/user/Manager1/Worker1 未送达。遇到 1 个死信。 经理开始监督
我发现使用 Autofac 无法足够快地创建 Actor。
当我添加 Thread.Sleep(20) 时,最后,正确创建 actor。
static void Main(string[] args)
{
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterType<WorkerManager>();
builder.RegisterType<Worker>();
var system = ActorSystem.Create("DiTestSystem");
IContainer container = builder.Build();
IDependencyResolver resolver = new AutoFacDependencyResolver(container, system);
var manageRef = system.ActorOf(system.DI().Props<WorkerManager>(), "Manager1");
Thread.Sleep(20); // ADDED THIS LINE
manageRef.Tell("Hello");
system.ActorSelection("/user/Manager1/Worker1").Tell("Hello");
Console.ReadLine();
}
我认为这是一个很大的问题,因为这种方法不能保证演员在睡眠时间总是create/resolve。
我一直打开这个问题,因为我认为这不是一个正确的答案。
这里的问题是竞争条件。无论您是否使用 DI 容器创建 actor,都可能发生这种情况。
在使用 actor 系统时,您需要记住一切都是异步发生的。在将消息发送给 WorkerManager
参与者后,您的代码可以继续,但这并不意味着该消息实际上已被接收和处理。它实际上被发布到一个邮箱,供演员准备好后在不同的线程上处理。
最好不要尝试直接访问 Worker
演员,因为您有一个 WorkerManager
演员。就像在现实生活中,你通常会要求经理安排一些工作来完成,然后经理会依次决定需要哪些工人,并将必要的工作分配给他们。
Akka.NET 有一个 router feature 对这种情况很有用。我已经用一些额外的日志记录和路由器配置更新了您的示例代码。
void Main()
{
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterType<Worker>();
builder.RegisterType<WorkerManager>();
var container = builder.Build();
var system = ActorSystem.Create("DITestSystem");
var resolver = new AutoFacDependencyResolver(container, system);
var manager = system.ActorOf(system.DI().Props<WorkerManager>(), "Manager");
Console.WriteLine("Program: Created Manager");
for (int i = 0; i < 10; i++)
{
manager.Tell("Hello");
}
Console.ReadKey(true);
}
public class Worker : ReceiveActor
{
public Worker()
{
Receive<string>(m => Console.WriteLine($"Worker {Context.Self.Path.Name} received: {m}"));
}
protected override void PreStart()
{
Console.WriteLine($"PreStart: {Context.Self.Path}");
}
}
public class WorkerManager : ReceiveActor
{
IActorRef worker;
public WorkerManager()
{
Receive<string>(m =>
{
Console.WriteLine($"Manager received: {m}");
worker.Tell(m);
});
}
protected override void PreStart()
{
Console.WriteLine($"PreStart: {Context.Self.Path}");
var props = Context.DI().Props<Worker>().WithRouter(new RoundRobinPool(5));
worker = Context.ActorOf(props, "Worker");
}
}
注意 WorkerManager
演员中的这一行,它为 Worker
演员配置路由器。
var props = Context.DI().Props<Worker>().WithRouter(new RoundRobinPool(5));
这将导致 ManagerActor
以循环方式将消息转发给 5 个子 Worker
参与者。消息路由已为您处理,因此无需直接与 Worker
参与者交互。
该示例现在还会在获得对 ManagerActor
的引用后立即向 ManagerActor
发送 10 条消息。
for (int i = 0; i < 10; i++)
{
manageRef.Tell("Hello");
}
随着播放中的更多消息和一些日志记录,您可以看到事物的顺序不是确定性的。这是 运行.
的输出Program: Created Manager
PreStart: akka://DITestSystem/user/Manager
Manager received: Hello
Manager received: Hello
Manager received: Hello
Manager received: Hello
Manager received: Hello
Manager received: Hello
Manager received: Hello
Manager received: Hello
Manager received: Hello
Manager received: Hello
PreStart: akka://DITestSystem/user/Manager/Worker/$b
PreStart: akka://DITestSystem/user/Manager/Worker/$d
PreStart: akka://DITestSystem/user/Manager/Worker/$f
Worker $b received: Hello
Worker $b received: Hello
Worker $f received: Hello
Worker $f received: Hello
PreStart: akka://DITestSystem/user/Manager/Worker/$c
Worker $c received: Hello
Worker $c received: Hello
PreStart: akka://DITestSystem/user/Manager/Worker/$e
Worker $d received: Hello
Worker $d received: Hello
Worker $e received: Hello
Worker $e received: Hello
这是另一个的输出。
Program: Created Manager
PreStart: akka://DITestSystem/user/Manager
PreStart: akka://DITestSystem/user/Manager/Worker/$b
PreStart: akka://DITestSystem/user/Manager/Worker/$c
PreStart: akka://DITestSystem/user/Manager/Worker/$d
PreStart: akka://DITestSystem/user/Manager/Worker/$f
PreStart: akka://DITestSystem/user/Manager/Worker/$e
Manager received: Hello
Manager received: Hello
Manager received: Hello
Manager received: Hello
Worker $d received: Hello
Worker $e received: Hello
Manager received: Hello
Manager received: Hello
Manager received: Hello
Manager received: Hello
Manager received: Hello
Worker $f received: Hello
Worker $e received: Hello
Manager received: Hello
Worker $f received: Hello
Worker $b received: Hello
Worker $b received: Hello
Worker $c received: Hello
Worker $c received: Hello
Worker $d received: Hello
您可以看到,在第一个 运行 中,WorkerManager
在创建任何子 Worker
actors 之前收到了所有消息。在第二个 运行 中,它在收到任何消息之前创建了所有子 Worker
actor。
要记住的要点是,最好通过消息进行交流,而不是对事情何时发生做出假设。