Какая разница между асинхронной моделью программирования и асинхронным шаблоном на основе событий?
Какой подход использовать и когда?
Какая разница между асинхронной моделью программирования и асинхронным шаблоном на основе событий?
Какой подход использовать и когда?
Модель асинхронного программирования (APM) - это модель, которую вы видите с парами BeginMethod(...)
и EndMethod(...)
.
Например, здесь Socket
используется реализация APM:
var socket = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
// ...
socket.BeginReceive(recvBuffer, 0, recvBuffer.Length,
SocketFlags.None, ReceiveCallback, null);
void ReceiveCallback(IAsyncResult result)
{
var bytesReceived = socket.EndReceive(result);
if (bytesReceived > 0) { // Handle received data here. }
if (socket.Connected)
{
// Keep receiving more data...
socket.BeginReceive(recvBuffer, 0, recvBuffer.Length,
SocketFlags.None, ReceiveCallback, null);
}
}
Асинхронный шаблон на основе событий (EAP) - это модель, которую вы видите с парами MethodAsync(...)
и CancelAsync(...)
. Обычно есть событие Completed
. BackgroundWorker
- хороший пример этого шаблона.
Начиная с С# 4.5, оба были заменены шаблоном async/await
, который использует библиотеку Task Parallelism (TPL). Вы увидите их, отмеченные Async
после имени метода и обычно возвращающие ожидаемые Task
или Task<TResult>
. Если вы можете настроить таргетинг на .NET 4.5, вы обязательно должны использовать этот шаблон для проекта APM или EAP.
Например, сжатие (потенциально большого) файла асинхронно:
public static async Task CompressFileAsync(string inputFile, string outputFile)
{
using (var inputStream = File.Open(inputFile, FileMode.Open, FileAccess.Read))
using (var outputStream = File.Create(outputFile))
using (var deflateStream = new DeflateStream(outputStream, CompressionMode.Compress))
{
await inputStream.CopyToAsync(deflateStream);
deflateStream.Close();
outputStream.Close();
inputStream.Close();
}
}
Из кода клиента POV:
EAP: вы настроили обработчик событий для события, чье имя заканчивается в "Completed", а затем вызовите метод, имя которого заканчивается на "Async". Иногда вы можете вызвать метод с именем "Отмена", который может отменить его.
APM: вы вызываете метод, имя которого начинается с "Begin", затем опробуйте его результат или получите обратный вызов, затем вызовите метод, начинающийся с "End".
Насколько я знаю об этих двух, APM реализуется на большинстве классов ввода-вывода BCL и WCF, в основном, на невыгружаемых операциях нижнего уровня (как и в случае отмены, вы просто игнорируете результат). EAP находится на более высокоуровневых классах, т.е. Для загрузки файла, где есть несколько шагов и какое-то значимое поведение отмены.
Итак, если вам нужно выбрать, что реализовать (и вы намеренно ограничиваете себя этими двумя), я предполагаю, что его до того, что вы делаете, можно отменить или нет.
Из клиентского кода POV вы не всегда получаете выбор. Вероятно, лучше всего использовать С# 4.5 Tasks, если вы можете, они могут работать с любым из более старых асинхронных механизмов через обертки.
Подробный ответ приведен в статье MSDN "Решение о том, как реализовать асинхронный шаблон на основе событий" .
Основная идея этой статьи (и короткий ответ на ваш вопрос) звучит так: "Построить шаблон на основе событий по умолчанию, с возможностью генерации шаблона IAsyncResult"