Akka.net 动态添加 child
Akka.net dynamically add child
有一个已配置的 ActorSystem
参与者按如下层次结构组织:
/user
/processes
/process1
/process2
/process3
为了生成这个方案,我使用了下一个 C# 代码:
// in entry point
IActorRef processesCoordinatorActorRef = ActorSystem.ActorOf(Props.Create<ProcessesCoordinatorActor>(), "processes");
// in ProcessesCoordinatorActor.cs:
IActorRef processOneActorRef = Context.ActorOf(Props.Create<ProccessActor>(), "process1");
IActorRef processTwoActorRef = Context.ActorOf(Props.Create<ProccessActor>(), "process2");
IActorRef processThreeActorRef = Context.ActorOf(Props.Create<ProccessActor>(), "process3");
我的问题是我想从入口点[=28]向process1
、process2
或process3
添加一个child演员=] 代码(在 ProcessActor 之外)。
但是现在我束手无策,因为 IActorRef
对我隐藏了某些演员实例。
如何解决?
必须在 parent 演员的 Context
中创建 child 演员。如果你想从外部触发这种情况,只需向 parent 发送一条消息并让它创建 child actor(例如 CreateChildActor
)。没办法在一个地方创建一个actor,然后让它"adopted"作为另一个actor的child。
一般来说(并不知道你到底想做什么),我的直觉是,从你的 top-level / entry-point 代码创建角色的层次结构不是一个好的方向你下去。您应该让层次结构中的 parent 参与者完成他们的创建工作和 supervising children。
如果您必须从入口点触发此过程,您可以使用 ActorSelection
and/or 将其解析为 [=15] 将 CreateChildActor
发送到层次结构中的任何位置=].
这是一个代码示例,展示了如何执行此操作,并让子进程在准备就绪后通知协调器 (also here as a Fiddle):
using System;
using System.Threading;
using Akka.Actor;
namespace ProcessActors
{
class Program
{
/// <summary>
/// Top-level process coordinator actor.
/// </summary>
public class ProcessesCoordinatorActor : ReceiveActor
{
public ProcessesCoordinatorActor()
{
Receive<CreateChildActor>(createRequest =>
{
Console.WriteLine("{0} creating child actor: {1}", Self.Path, createRequest.ChildName);
var child = Context.ActorOf(createRequest.ChildProps, createRequest.ChildName);
if (createRequest.ActorToNotify != null)
createRequest.ActorToNotify.Tell(new ReadyForWork(child));
});
Receive<ReadyForWork>(ready =>
{
Console.WriteLine("Coordinator sees worker ready: {0}", ready.Worker.Path);
});
ReceiveAny(o =>
{
Console.WriteLine("{0} received {1}", Self.Path, o);
});
}
}
/// <summary>
/// Actor for a given process.
/// </summary>
public class ProcessActor : ReceiveActor
{
public ProcessActor()
{
Receive<CreateChildActor>(createRequest =>
{
Console.WriteLine("{0} creating child actor: {1}", Self.Path, createRequest.ChildName);
var child = Context.ActorOf(createRequest.ChildProps, createRequest.ChildName);
if (createRequest.ActorToNotify != null)
createRequest.ActorToNotify.Tell(new ReadyForWork(child));
});
ReceiveAny(o =>
{
Console.WriteLine("{0} received {1}", Self.Path, o);
});
}
}
/// <summary>
/// Sub-process.
/// </summary>
public class SubprocessActor : ReceiveActor
{
public SubprocessActor()
{
ReceiveAny(o =>
{
Console.WriteLine("{0} received {1}", Self.Path, o);
});
}
}
public static void Main(string[] args)
{
using (var system = ActorSystem.Create("MyActorSystem"))
{
Console.WriteLine("Starting up.");
var coordinator = system.ActorOf(Props.Create(() => new ProcessesCoordinatorActor()), "processes");
var processProps = Props.Create(() => new ProcessActor());
// create process actors
coordinator.Tell(new CreateNewProcess("process1", processProps));
coordinator.Tell(new CreateNewProcess("process2", processProps));
coordinator.Tell(new CreateNewProcess("process3", processProps));
var subprocessProps = Props.Create(() => new SubprocessActor());
// tiny sleep to let everything boot
Thread.Sleep(TimeSpan.FromMilliseconds(50));
// get handle to an actor somewhere down in the hierarchy
var process1 = system.ActorSelection("/user/processes/process1").ResolveOne(TimeSpan.FromSeconds(1)).Result;
// create subprocess of process1 and notify the coordinator of new subprocess actor
process1.Tell(new CreateNewSubprocess("subprocess1", subprocessProps, coordinator));
Console.ReadLine();
}
}
#region Messages
/// <summary>
/// Command to create ChildProps actor and notify another actor about it.
/// </summary>
public class CreateChildActor
{
public CreateChildActor(string childName, Props childProps, IActorRef actorToNotify)
{
ChildName = childName;
ActorToNotify = actorToNotify;
ChildProps = childProps;
}
public CreateChildActor(string childName, Props childProps)
: this(childName, childProps, null)
{
}
public Props ChildProps { get; private set; }
public string ChildName { get; private set; }
public IActorRef ActorToNotify { get; private set; }
}
public class CreateNewProcess : CreateChildActor
{
public CreateNewProcess(string childName, Props childProps, IActorRef actorToNotify)
: base(childName, childProps, actorToNotify)
{
}
public CreateNewProcess(string childName, Props childProps)
: this(childName, childProps, null)
{
}
}
public class CreateNewSubprocess : CreateChildActor
{
public CreateNewSubprocess(string childName, Props childProps, IActorRef actorToNotify)
: base(childName, childProps, actorToNotify)
{
}
public CreateNewSubprocess(string childName, Props childProps)
: this(childName, childProps, null)
{
}
}
/// <summary>
/// Report to another actor when ready.
/// </summary>
public class ReadyForWork
{
public ReadyForWork(IActorRef worker)
{
Worker = worker;
}
public IActorRef Worker { get; private set; }
}
#endregion
}
}
有一个已配置的 ActorSystem
参与者按如下层次结构组织:
/user
/processes
/process1
/process2
/process3
为了生成这个方案,我使用了下一个 C# 代码:
// in entry point
IActorRef processesCoordinatorActorRef = ActorSystem.ActorOf(Props.Create<ProcessesCoordinatorActor>(), "processes");
// in ProcessesCoordinatorActor.cs:
IActorRef processOneActorRef = Context.ActorOf(Props.Create<ProccessActor>(), "process1");
IActorRef processTwoActorRef = Context.ActorOf(Props.Create<ProccessActor>(), "process2");
IActorRef processThreeActorRef = Context.ActorOf(Props.Create<ProccessActor>(), "process3");
我的问题是我想从入口点[=28]向process1
、process2
或process3
添加一个child演员=] 代码(在 ProcessActor 之外)。
但是现在我束手无策,因为 IActorRef
对我隐藏了某些演员实例。
如何解决?
必须在 parent 演员的 Context
中创建 child 演员。如果你想从外部触发这种情况,只需向 parent 发送一条消息并让它创建 child actor(例如 CreateChildActor
)。没办法在一个地方创建一个actor,然后让它"adopted"作为另一个actor的child。
一般来说(并不知道你到底想做什么),我的直觉是,从你的 top-level / entry-point 代码创建角色的层次结构不是一个好的方向你下去。您应该让层次结构中的 parent 参与者完成他们的创建工作和 supervising children。
如果您必须从入口点触发此过程,您可以使用 ActorSelection
and/or 将其解析为 [=15] 将 CreateChildActor
发送到层次结构中的任何位置=].
这是一个代码示例,展示了如何执行此操作,并让子进程在准备就绪后通知协调器 (also here as a Fiddle):
using System;
using System.Threading;
using Akka.Actor;
namespace ProcessActors
{
class Program
{
/// <summary>
/// Top-level process coordinator actor.
/// </summary>
public class ProcessesCoordinatorActor : ReceiveActor
{
public ProcessesCoordinatorActor()
{
Receive<CreateChildActor>(createRequest =>
{
Console.WriteLine("{0} creating child actor: {1}", Self.Path, createRequest.ChildName);
var child = Context.ActorOf(createRequest.ChildProps, createRequest.ChildName);
if (createRequest.ActorToNotify != null)
createRequest.ActorToNotify.Tell(new ReadyForWork(child));
});
Receive<ReadyForWork>(ready =>
{
Console.WriteLine("Coordinator sees worker ready: {0}", ready.Worker.Path);
});
ReceiveAny(o =>
{
Console.WriteLine("{0} received {1}", Self.Path, o);
});
}
}
/// <summary>
/// Actor for a given process.
/// </summary>
public class ProcessActor : ReceiveActor
{
public ProcessActor()
{
Receive<CreateChildActor>(createRequest =>
{
Console.WriteLine("{0} creating child actor: {1}", Self.Path, createRequest.ChildName);
var child = Context.ActorOf(createRequest.ChildProps, createRequest.ChildName);
if (createRequest.ActorToNotify != null)
createRequest.ActorToNotify.Tell(new ReadyForWork(child));
});
ReceiveAny(o =>
{
Console.WriteLine("{0} received {1}", Self.Path, o);
});
}
}
/// <summary>
/// Sub-process.
/// </summary>
public class SubprocessActor : ReceiveActor
{
public SubprocessActor()
{
ReceiveAny(o =>
{
Console.WriteLine("{0} received {1}", Self.Path, o);
});
}
}
public static void Main(string[] args)
{
using (var system = ActorSystem.Create("MyActorSystem"))
{
Console.WriteLine("Starting up.");
var coordinator = system.ActorOf(Props.Create(() => new ProcessesCoordinatorActor()), "processes");
var processProps = Props.Create(() => new ProcessActor());
// create process actors
coordinator.Tell(new CreateNewProcess("process1", processProps));
coordinator.Tell(new CreateNewProcess("process2", processProps));
coordinator.Tell(new CreateNewProcess("process3", processProps));
var subprocessProps = Props.Create(() => new SubprocessActor());
// tiny sleep to let everything boot
Thread.Sleep(TimeSpan.FromMilliseconds(50));
// get handle to an actor somewhere down in the hierarchy
var process1 = system.ActorSelection("/user/processes/process1").ResolveOne(TimeSpan.FromSeconds(1)).Result;
// create subprocess of process1 and notify the coordinator of new subprocess actor
process1.Tell(new CreateNewSubprocess("subprocess1", subprocessProps, coordinator));
Console.ReadLine();
}
}
#region Messages
/// <summary>
/// Command to create ChildProps actor and notify another actor about it.
/// </summary>
public class CreateChildActor
{
public CreateChildActor(string childName, Props childProps, IActorRef actorToNotify)
{
ChildName = childName;
ActorToNotify = actorToNotify;
ChildProps = childProps;
}
public CreateChildActor(string childName, Props childProps)
: this(childName, childProps, null)
{
}
public Props ChildProps { get; private set; }
public string ChildName { get; private set; }
public IActorRef ActorToNotify { get; private set; }
}
public class CreateNewProcess : CreateChildActor
{
public CreateNewProcess(string childName, Props childProps, IActorRef actorToNotify)
: base(childName, childProps, actorToNotify)
{
}
public CreateNewProcess(string childName, Props childProps)
: this(childName, childProps, null)
{
}
}
public class CreateNewSubprocess : CreateChildActor
{
public CreateNewSubprocess(string childName, Props childProps, IActorRef actorToNotify)
: base(childName, childProps, actorToNotify)
{
}
public CreateNewSubprocess(string childName, Props childProps)
: this(childName, childProps, null)
{
}
}
/// <summary>
/// Report to another actor when ready.
/// </summary>
public class ReadyForWork
{
public ReadyForWork(IActorRef worker)
{
Worker = worker;
}
public IActorRef Worker { get; private set; }
}
#endregion
}
}