3

Edit - After reading the three answers below, I've realized that I'm asking nonsense ! Apologies for wasting some of your precious time, and thanks for clarifying alot of misunderstandings, really! :)

I were assuming apples and pipe wrenches were the same thing in the way async/await and threads are solution for similar concerns. Async/await and Threads both addresses UI responsiveness, but not in the same way. The former is a pattern to be used when several desired results can be gathered asynchronously (in order to improve user experience for example), hence why it's called "async". Heavy works, those that take several seconds to hours has to be off loaded on another thread to keep UI responsive. Those two are completely different concerns.

No matter how I may edit this question, there is no way to ask such async/await with or without threading concern as they are completely different things, can be used together (in so many ways) or separately. The statement .2 below said it all (apart a "invocation" misconception) but I didn't truely understood its true meaning from the start.

I guess I should have deleted the question from the moment I had doubts, but I couldn't understand how far it was a dumb one before actually reading some answers. However, this may also help other to have a better understanding of what async/await is about.

By the way, I don't know what answer to mark as answer as they all have valuable informations.


Original post:

It's fair to note that I'm "yet another async/await beginner". However, What I've understood so far are:

  1. async/await doesn't create threads ! Never ! They run on the same thread as the caller.
  2. async/await are not parallel tasks. They just defines a pattern where an async block of code get executed the moment an await is invoked at caller level (or so - I know my understanding is slightly wrong, but that's how I can clearly picture it in mind)
  3. No code block is executed asynchronuously if that block doesn't contain an await keyword.
  4. async/await appears to work well with some I/O tasks, but seems not that wonderful on most high CPU computations.
  5. async/await seems to fail with Thread.Sleep (should use Task.Delay instead) or in case of Exception with Finally block.

Based on the above, and to simplify things, I think async/await is just an improved form of goto, capable of jumping from a method step to another method step, because the goto call can "fly" (be delayed) until an await is encountered ! (sorry to simplify things that far)

I've tested both I/O and CPU codes without additional threads, both heavy, and both produced unresponsive UI until everything was completed.

My observaton is:

Without asynchronous capable things like :

  • threads explicitely defined using one of the numerous .net objects in the framework, or their members that create threads on their own
  • or IO devices that are designed to work asynchronously from the start at hardware level (CPU)

async/await are just plain synchronous patterns; meaning, there is no asynchronous-like thing anywhere with just async/await keywords.

The question is: is the above observation true, or am I missing some important thing about async/await ?


Side notes :

I've read this blog post (There Is No Thread, Stephen Cleary's Blog). He states that there is no thread (totally agree) but it doesn't contradict with my observation that, at pure programmer code level without asynchronous devices involved, you can't have a responsive UI unless you delegate the heavy tasks in another thread. My concern is not the awaitable aspect of the pattern, as I said, it's like a flying goto; I want to make sure I'm not using async/await blindly just for the sake of using something new.

.ConfigureAwait(false) : seems to involve a ThreadPool to me, which is why the UI thread is still responsive...

Community
  • 1
  • 1
Karl Stephen
  • 1,120
  • 8
  • 22
  • 1
    This is not a question. – i3arnon Oct 19 '15 at 19:26
  • 1
    Doesn't [_"The major difference \[with manual threading\] is that async/await releases the current thread completely while waiting for completion"_](http://stackoverflow.com/a/18299910/266143) from [Why Use Async/Await Over Normal Threading or Tasks?](http://stackoverflow.com/questions/18298946/why-use-async-await-over-normal-threading-or-tasks) answer your question? – CodeCaster Oct 19 '15 at 19:30
  • 1
    @KarlStephen: Side note: On Windows, all device I/O has to be asynchronous. – Stephen Cleary Oct 19 '15 at 20:04

3 Answers3

4

Async-await is a pattern that allows you to write code that closely resembles synchronous code but can actually execute asynchronously. This relies on a lot of work done by the compiler. That's all.

Async-await doesn't create asynchronous operations, it just allows you to use them in a simple way and still be asynchronous, unlike before using BeginXXX/EndXXX.

It's true that async is mostly useful with I/O, because most asynchronous operations are I/O operations, but there are different ones like Task.Delay, asynchronous synchronization mechanisms or asynchronously waiting for an event.

About your specific points:

  1. Async-await doesn't create threads. Async methods start running on the caller thread, don't use any thread for the actual asynchronous operation and resume on a ThreadPool thread or one defined by the SynchronizationContext or TaskScheduler.
  2. Await isn't invoked. When an async method reaches an await on an uncompleted task the rest of the method is scheduled as a continuation that will run when that task is completed.
  3. Pretty much. You need to await an asynchronous operation for your async method to be asynchronous.
  4. Async-await works with both. If your operation isn't asynchronous though, there's no point in using async-await.
  5. Async-await doesn't fail with Thread.Sleep. It's just wasteful to use Thread.Sleep as it blocks a thread. That's why you use Task.Delay. You can now await in finally with C# 6.

And finally:

meaning, there is no asynchronous-like thing anywhere with just async/await keywords.

Yes, marking a method with the async keyword doesn't make anything run asynchronously. It only allows you to use await and wrap the result in a Task.

i3arnon
  • 113,022
  • 33
  • 324
  • 344
  • Thanks for pointing out other usages of async/await, like waiting for an event. I didn't knew that was possible. I failed to point out in OP the fact that I'm concerned about responsive UI while performing heavy tasks. It is now clear to me that **async/await has nothing to do with keeping UI responsive** (please forgive the beginner I am - the MSDN somewhat mislead my understanding, about async improves responsiveness; it all depends on where, how and with which objects async/await are used) – Karl Stephen Oct 19 '15 at 19:56
  • @KarlStephen async-await very much helps with UI responsiveness, but only if you offload heavy work to another thread (e.g. with `Task.Run`) and await it. – i3arnon Oct 19 '15 at 19:59
  • Yeah ! It's great when for example you're uploading multiples files at the same time and displays "uploaded!" in five textboxes. There, I completely understand the use of async/await pattern. The fact that offloading heavy work is still required is a great clarification (for most async/await beginners - mostly the understanding of awaitable tasks that ought to not be heavy work, like just updating the value of a textbox) That statement helps alot to select the correct pattern, and only a few has stated it that clear among the readings I've had. – Karl Stephen Oct 19 '15 at 20:12
4

You may find my async intro helpful.

I would say that async and await are the most elegant way to consume asynchronous operations. As a side product, async also creates a higher-level asynchronous operation (if the method returns a Task/Task<T>). However, they are not a good way for creating asynchronous operations out of nothing.

So I would disagree with this statement:

async/await are just plain synchronous patterns

However, I would agree with the statement that await just breaks up an async method into multiple synchronous parts.

If you have CPU-bound code and you don't want to block the UI thread, then you could use something like Task.Run to push that code onto a thread pool thread. The UI code can then await the task returned from Task.Run.

Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
  • I've read it. Thanks (one of the very first pages on topic I opened). And that's why I asked the question (or rather interpretation). The main misunderstanding for us beginners lays there : _await just breaks up an async method into multiple synchronous parts._ Best description of the thing so far IMHO; thanks. It's asynchronous, indeed, but the whole series of code blocks has to be completed before being able to have the application at idle (kind of, and render every pending UI updates not covered by the code blocks) – Karl Stephen Oct 19 '15 at 20:33
  • @KarlStephen: Not quite. Every `await` is an opportunity for the UI to update (assuming the code is written correctly). So when an asynchronous operation completes, only the *next* part has to execute (up to the next `await`), not all the parts. – Stephen Cleary Oct 19 '15 at 21:17
  • So there is something wrong in my code. Maybe because of the await and progressbar.value put inside a for loop (i=1..100). The await result is just an int32 value returned by an async method taking `i` as a parameter, pauses for one second, then returns `i`, that is assigned to progress.value. The UI hangs for about 100 seconds, then the progress jumps from 0 to 100. Anyway, I'm editing the question as I asked some incredible nonsense after reading your answers... – Karl Stephen Oct 19 '15 at 21:42
  • 1
    @KarlStephen: That depends on how your "pauses for one second" is implemented. It should be `await Task.Delay(1000);`. – Stephen Cleary Oct 19 '15 at 23:08
2

There are two distinct concepts here that you are mixing up. Being asynchronous and parallel are not the same thing. While asynchronous operations can hide multithreading under the hood, they don't necessarily do.

The async / await keywords in C# are just syntactic sugar for expressing thoughts like “when operation A is done, do operation B”. Whether or not operation A runs on another thread is an implementation detail you don't care about.

Basically, you let the compiler and the framework figure it out for you.

If you think of it, async / await can be conceptionally somewhat similar to how events and event loops work. Perhaps the event syntax was not flexible enough and that's why they introduced these new keywords. Personally I believe that it's kind of in the same legaue as promises in JavaScript or how the event loop works in Node.js. I'm not saying that it works similarly but it does solve very similar problems.

Venemo
  • 18,515
  • 13
  • 84
  • 125