TPL TaskFactory.FromAsync vs Tasks with blocking methods

19,834

Solution 1

You absolutely want to use FromAsync when an API offers a BeginXXX/EndXXX version of a method. The difference is that, in the case of something like Stream or Socket or WebRequest, you'll actually end up using async I/O underneath the covers (e.g. I/O Completion Ports on Windows) which is far more efficient than blocking multiple CPU threads doing a synchronous operation. These methods provide the best way to achieve I/O scalability.

Check out this section of the .NET SDK on MSDN entitled TPL and Traditional .NET Asynchronous Programming for more information on how to combine these two programming models to achieve async nirvana.

Solution 2

Following a copy from a external link:

Yes. In .NET 4, the Task Parallel Library includes a built in wrapper for the APM pattern (Begin/End): Task.Factory.FromAsync. For example, if you wanted to create a task for a call to Stream's BeginRead/EndRead method, you could do:

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. 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

Share:
19,834
Jonathan Matheus
Author by

Jonathan Matheus

Updated on June 05, 2022

Comments

  • Jonathan Matheus
    Jonathan Matheus almost 2 years

    I was wondering if there were any performance implications between using TPL TaskFactory.FromAsync and using TaskFactory.StartNew on blocking versions of the methods. I'm writing a TCP server that will support no more than 100 concurrent connections. After writing code with the first option & chaining multiple read & write operations with continue with, I was left with ugly, hard to debug code.

    I believe writing code with the synchronous version & then wrapping it with a Task would decrease complexity & increase testability, but I'm worried about the performance implications of doing this.

    For example, are there any performance differences between these 2 calls:

    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));
    
  • sra
    sra over 12 years
    please provide content of external links. Otherwise your answer is worthless if the link breaks.
  • Kevin Kalitowski
    Kevin Kalitowski almost 12 years
    Do you have any sources which say calling a web method (for example) using Begin/End with Async is better than using the synchronous version with Async? What you say makes sense, I just like to read it somewhere official.
  • John Smith
    John Smith about 9 years
    if msdn breaks, we are all worthless