У меня есть иерархия субъектов в Akka.Net, и мне интересно, правильно ли я выбрал способ что-то сделать, или есть лучшие / более простые способы достичь того, чего я хочу.
Мой конкретный пример: я создаю субъект User в ответ на вход пользователя в систему, и при создании этого субъекта мне нужны два фрагмента данных, чтобы завершить построение объекта актер.
Если бы это был обычный .NET-код, у меня могло бы получиться что-то вроде следующего ...
public Task<User> LoadUserAsync (string username)
{
IProfileService profileService = ...;
IMessageService messageService = ...;
var loadProfileTask = profileService.GetUserProfileAsync(username);
var loadMessagesTask = messageService.GetMessagesAsync(username);
Task.WaitAll(loadProfileTask, loadMessagesTask);
// Now construct the user from the result of both tasks
var user = new User
{
Profile = loadProfileTask.Result,
Messages = loadMessagesTask.Result
}
return Task.FromResult(user);
}
Здесь я использую WaitAll, чтобы дождаться завершения подчиненных задач и позволить им работать одновременно.
Мой вопрос: если бы я хотел сделать то же самое в Akka.Net, был бы следующий способ сделать это наиболее часто? Графически я создал следующее ...
Когда я создаю своего актора User, я затем создаю (временный) User Loader Actor, задача которого состоит в том, чтобы получить полные сведения о пользователе путем вызова актора Profile и субъекта Messages. Листовые акторы, получающие данные, следующие ...
public class UserProfileLoader : ReceiveActor
{
public UserProfileLoader()
{
Receive<LoadUserRequest>(msg =>
{
// Load the user profile from somewhere
var profile = new UserProfile();
// And respond to the Sender
Sender.Tell(profile);
Self.Tell(PoisonPill.Instance);
});
}
}
public class UserMessagesLoader : ReceiveActor
{
public UserMessagesLoader()
{
Receive<LoadUserRequest>(msg =>
{
// Load the messages from somewhere
var messages = new List<Message>();
// And respond to the Sender
Sender.Tell(messages);
Self.Tell(PoisonPill.Instance);
});
}
}
На самом деле не имеет значения, откуда они берут данные для этого обсуждения, но оба просто отвечают на запрос, возвращая некоторые данные.
Затем у меня есть актер, который координирует двух участников сбора данных ...
public class UserLoaderActor : ReceiveActor
{
public UserLoaderActor()
{
Receive<LoadUserRequest>(msg => LoadProfileAndMessages(msg));
Receive<UserProfile>(msg =>
{
_profile = msg;
FinishIfPossible();
});
Receive<List<Message>>(msg =>
{
_messages = msg;
FinishIfPossible();
});
}
private void LoadProfileAndMessages(LoadUserRequest msg)
{
_originalSender = Sender;
Context.ActorOf<UserProfileLoader>().Tell(msg);
Context.ActorOf<UserMessagesLoader>().Tell(msg);
}
private void FinishIfPossible()
{
if ((null != _messages) && (null != _profile))
{
_originalSender.Tell(new LoadUserResponse(_profile, _messages));
Self.Tell(PoisonPill.Instance);
}
}
private IActorRef _originalSender;
private UserProfile _profile;
private List<Message> _messages;
}
Это просто создает двух подчиненных субъектов, отправляет им сообщение для взлома, а затем ожидает ответа обоих перед отправкой обратно всех данных, которые были собраны исходному запрашивающему.
Итак, кажется ли это разумным способом скоординировать два несопоставимых ответа, чтобы объединить их? Есть ли более простой способ сделать это, чем сделать это самому?
Заранее благодарим за ответы!
User
субъект отправить эти два запроса напрямую? - person Bartosz Sypytkowski   schedule 16.02.2016WhenAll
для обеих подзадач, а затем вернул бы эту задачу, чтобы вызывающий могPipeTo(Self)
, когда это будет сделано ... Я знаю, что мы проповедуем детям опасную работу, но нужно учитывать, если вы действительно выиграете от этого, или если это просто приведет к раздуванию кода ... - person Roger Johansson   schedule 16.02.2016