Question

So, in C#, I understand the historical difference between the two vaguely; a Task is a newer concept and the highest level concurrency native C# offers.

AsyncResult is a bit more ambiguous. For example, the docs say BeginRead relies on the underlying stream for non blocking behavior.

I know ReadAsync creates a Task which is handled by a Scheduler on the ThreadPool and therefore is guaranteed to not block, but then I read about C# delegates and Begin/EndInvoke which allow "any synchronous method to be asynchronous"

Is this true? As the documentation around BeginRead seems to indicate it still blocks if the underlying stream blocks. Is this equivalent to creating a Task, just less developer friendly?

Is a Task always preferred to an AsyncResult? Why or why not?

I surely hope this is the correct place to ask this.

Was it helpful?

Solution

I know ReadAsync creates a Task which is handled by a Scheduler on the ThreadPool and therefore is guaranteed to not block, but then I read about C# delegates and Begin/EndInvoke which allow "any synchronous method to be asynchronous"

Is this true?

Yes, ReadAsync will not block, and yes, it will use the thread pool.

And yes delegate.BeginInvoke and delegate.EndInvoke will not block either. And yes, they use the thread pool. And you should avoid them. Please have a look at Difference between delegate.BeginInvoke and using ThreadPool threads in C#.


As the documentation around BeginRead seems to indicate it still blocks if the underlying stream blocks. Is this equivalent to creating a Task, just less developer friendly?

Stream.BeginRead is virtual. The class that derives from Stream can mess with it. So it might block on some streams. It should not be a problem for IO stream. However, the reference source for Stream also suggest that some platform could use blocking streams if they do not support async IO.


Is a Task always preferred to an AsyncResult? Why or why not?

Yes.

AsyncResult is a promise, kind of like how Task is a promise. Except, it is worse.

An AsyncResult could be completed synchronously, or asynchronously. Kind of like Task. But if the AsyncResult did not complete synchronously, you get a WaitHandle (AsyncResult.AsyncWaitHandle). And that means you will either have to pool or block on a thread to to wait on it...

Or do you? You can use ThreadPool.RegisterWaitForSingleObject to wait on the WaitHandle from the AsyncResult.

Add to that that AsyncResult does not express cancellation nor timeout by itself. You can specify your timeout to wait on the WaitHandle... but for cancellation you might be forced to create another WaitHandle for the cancellation then use WaitHandle.WaitAny... and of course handle the end method appropriately.

Finally, AsyncResult is the promise producer facing API, IAsyncResult is the promise consumer facing API. Because of this, you probably don't want to expose any AsyncResult in your API, only expose IAsyncResult if anything.

I would advice against using AsyncResult at all. If you use AsyncResult, messing with the producer is just a cast appart.

Of course, Task is better.

Licensed under: CC-BY-SA with attribution
scroll top