Difference Between AsyncResult and Task in c#
https://softwareengineering.stackexchange.com/questions/404876
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.
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.