4

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.

1 Answer 1

3

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.

4
  • I was mistaken, I meant to say IAsyncResult the entire time, but this explanation makes sense. I was specifically wondering about the differences between Stream.BeginRead and Stream.ReadAsync. is it safe to say one handles a higher concurrent load than the other? i.e. if I want to make an application that makes thousands of arbitrary reads concurrently, would one perform better or is the difference mostly just in code? Commented Feb 8, 2020 at 17:42
  • @user1538301 hmm... I would argue that BeginRead is lower level, you probably can built something for such use case which is more performant by avoiding some unnecessary overhead (I would have to actually try and benchmark). It is, of course, harder to use, and thus it will be easier to introduce bugs using BeginRead. Which means that, as developer, you will be less productive. Now, it is economics.
    – Theraot
    Commented Feb 8, 2020 at 18:05
  • @user1538301 thinking about it, using BeginRead and EndRead wil likely result in more unmanaged resources (WaitHandle), while Task would avoid those.
    – Theraot
    Commented Feb 8, 2020 at 19:45
  • I shall benchmark it and find out. Thanks Commented Feb 8, 2020 at 22:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.