Если вам нужна производительность и асинхронность на самом высоком уровне, я рекомендую изучить порты завершения.Это то, что в конечном итоге скрыто в ядре Windows, и это потрясающе.Когда я использовал их, я использовал C ++, даже из-за этого обнаружил ошибку ядра, , но Я был ограничен языком.
Я видел эту статью на CodeProject, которую, возможно, стоит изучить, чтобы узнать, где можно продвинуть свою идею и / или использовать имеющийся код.
Природа портов завершения заключается в работе с обратными вызовами.То есть, как правило, вы «помещаете» запрос в очередь, и когда что-то попадает туда, запрос читается, а указанный обратный вызов читается.На самом деле это очередь, но, как я уже сказал, на самом низком (управляемом) уровне (до того, как попасть почти на металл).
РЕДАКТИРОВАТЬ: Я написал что-то вродеУтилита тестирования FTP-сервера / клиента с портами завершения, поэтому базовый процесс такой же - чтение и запись команд в режиме в очереди .Надеюсь, это поможет.
РЕДАКТИРОВАТЬ # 2: Хорошо, вот что я хотел бы сделать, основываясь на ваших отзывах и комментариях.У меня была бы «исходящая очередь», ConcurrentQueue<Message>
.Вы можете создать отдельную ветку для отправки сообщений, удалив каждое сообщение из очереди. Заметьте, если вы хотите, чтобы оно было немного более "безопасным", я предлагаю заглянуть в сообщение, отправить его, а затем снять его. В любом случае, класс Message может быть внутренним и выглядеть примерно так:
private class Message {
public string Command { get; set; }
... additonal properties, like timeouts, etc. ...
}
В синглтон-классе (я назову это CommunicationService
) у меня также будет ConcurrentBag<Action<Response>>
.Теперь начинается самое интересное: о).Когда отдельное предприятие хочет что-то сделать, оно регистрируется, например, если у вас есть TemepratureMeter
, я бы сделал так:
public class TemperatureMeter {
private AutoResetEvent _signal = new AutoResetEvent(false);
public TemperatureMeter {
CommunicationService.AddHandler(HandlePotentialTemperatureResponse);
}
public bool HandlePotentialTemperatureResponse(Response response) {
// if response is what I'm looking for
_signal.Set();
// store the result in a queue or something =)
}
public decimal ReadTemperature() {
CommunicationService.SendCommand(Commands.ReadTemperature);
_signal.WaitOne(Commands.ReadTemperature.TimeOut); // or smth like this
return /* dequeued value from the handle potential temperature response */;
}
}
А теперь, в вашем CommunicationService, когда выполучить ответ, вы просто к
foreach(var action in this._callbacks) {
action(rcvResponse);
}
Вуаля, разделение проблем.Отвечает ли он на ваш вопрос лучше?
Другая возможная тактика - соединить сообщение и обратный вызов, но при этом обратный вызов будет Func<Response, bool>
, и поток диспетчера проверяет, верен ли результат, возвращенный из Func,тогда этот обратный вызов расположен .