TPL TaskFactory.FromAsync vs Задачи с методами блокировки
Мне было интересно, были ли какие-либо последствия для производительности между использованием TPL TaskFactory.FromAsync
и использованием TaskFactory.StartNew
для блокировки версий методов. Я пишу TCP-сервер, который будет поддерживать не более 100 одновременных подключений. После написания кода с первой опцией и цепочки нескольких операций чтения и записи с продолжением, я остался с уродливым, трудно отлаживающим кодом.
Я считаю, что писать код с синхронной версией, а затем обертывать ее с помощью Задачи, уменьшит сложность и увеличит тестируемость, но я беспокоюсь о последствиях производительности для этого.
Например, существуют ли различия в производительности между этими двумя вызовами:
NetworkStream stream;
byte[] data;
int bytesRead;
//using FromAsync
Task<int> readChunk = Task<int>.Factory.FromAsync (
stream.BeginRead, stream.EndRead,
data, bytesRead, data.Length - bytesRead, null);
//using StartNew with blocking version
Task<int> readChunk2 = Task<int>.Factory.StartNew(() =>
stream.Read(data, bytesRead, data.Length - bytesRead));
Ответы
Ответ 1
Вы абсолютно хотите использовать FromAsync
, когда API предлагает версию метода BeginXXX/EndXXX. Разница в том, что в случае чего-то вроде Stream
или Socket
или WebRequest
, вы фактически будете использовать асинхронный ввод-вывод под обложками (например, порты завершения ввода/вывода в Windows), которые далеки более эффективный, чем блокирование нескольких потоков ЦП, выполняющих синхронную работу. Эти методы обеспечивают наилучший способ достижения масштабируемости ввода/вывода.
Ознакомьтесь с этим разделом .NET SDK в MSDN под названием TPL и традиционным асинхронным программированием .NET для получения дополнительной информации о том, как объединить эти две модели программирования для достижения async нирвана.
Ответ 2
После копирования с внешней ссылки:
Да. В .NET 4 параллельная библиотека задач включает встроенную оболочку для шаблона APM (начало/конец): Task.Factory.FromAsync. Например, если вы хотите создать задачу для вызова Stream BeginRead/EndRead, вы можете сделать:
Stream s = ...;
byte [] buffer = ...;
Task<int> numBytesRead = Task<int>.Factory.FromAsync(s.BeginRead, s.EndRead, buffer, 0, buffer.Length, null);
// or with await
int numBytesRead = await Task<int>.Factory.FromAsync(s.BeginRead, s.EndRead, buffer, 0, buffer.Length, null);
Under the covers, FromAsync is just built on top of TaskCompletionSource<TResult>. A simple version of FromAsync for this read example would look something like:
var tcs = new TaskCompletionSource<TResult>();
s.BeginRead(buffer, 0, buffer.Length, iar =>
{
try { tcs.SetResult(s.EndRead(iar)); }
catch(Exception exc) { tcs.SetException(exc); }
}, null);
Task<int> numBytesRead = tcs.Task;
http://social.msdn.microsoft.com/Forums/en/async/thread/ed8a14e8-d19a-42d1-bc3f-7017bdfed09c