53

I have read a lot of articles and still cant get understand this part.

Consider this code :

    private async void button1_Click(object sender, EventArgs e)
    {
        await Dosomething();
    }

    private async Task<string> Dosomething()
    {
        await Task.Run((() => "Do Work"));
        return "I am done";
    }

First question:

When I click the button, it will Call DoSomething and await a Task that creates a Thread from the threadpool by calling Task.Run ( if I am not mistaken ) and all of this runs asynchronously. So I achieved creating a thread that does my work but doing it asynchronously? But consider that I don't need any result back, i just want the work to be done without getting any result back, is there really a need to use async/await , and if so, how?

Second question:

When running a thread asynchronously, how does that work? Is it running on the main UI but on a separate thread or is it running on a separate thread and separate is asynchronously inside that method?

Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
syncis
  • 605
  • 1
  • 5
  • 8
  • i'm not that familiar with async/await yet, but I believe that whether or not a new thread is used is dependent on what the OS decides - i.e., you're not guaranteed execution on a new thread. – Tim Sep 22 '15 at 20:32
  • 2
    @Tim Nit: The OS will start a new thread if told to do so. Any relevant thread pooling, etc, happens in .NET itself. – user2864740 Sep 22 '15 at 20:33
  • @user2864740 - Thanks for the clarification :) – Tim Sep 22 '15 at 20:36
  • 1
    async/await will never create a new thread - otherwise we would all have to write the threadsafe safe code for everything after the awaited called which is exactly what async await is trying avoid. Whether the awaited method itself spawns a new thread async/await has nothing to do with, the awaited called always runs on the same thread that called it. – markmnl Feb 20 '17 at 06:32
  • 1
    @markmnl - however, anyone reading your comment here should also read the discussion between you and Matias [under his answer](https://stackoverflow.com/a/32726747/199364), where it is clarified that, the *continuation after* the await completes *might be on a different thread*, depending on the current SynchronizationContext. Fortunately, for a UI thread, the context *does* ensure returning to that UI thread. So for UI, its definitely all one thread. [I mean, if do `await`, but *don't* do `Task.Run`.] – ToolmakerSteve Jun 27 '18 at 07:59

3 Answers3

31
  1. The purpose of creating Async methods is so you can Await them later. Kind of like "I'm going to put this water on to boil, finish prepping the rest of my soup ingredients, and then come back to the pot and wait for the water to finish boiling so I can make dinner." You start the water boiling, which it does asynchronously while you do other things, but eventually you have to stop and wait for it. If what you want is to "fire-and-forget" then Async and Await are not necessary.

Simplest way to do a fire and forget method in C#?

  1. Starting a new task queues that task for execution on a threadpool thread. Threads execute in the context of the process (eg. the executable that runs your application). If this is a web application running under IIS, then that thread is created in the context of the IIS worker process. That thread executes separately from the main execution thread, so it goes off and does its thing regardless of what your main execution thread is doing, and at the same time, your main execution thread moves on with its own work.
Community
  • 1
  • 1
DVK
  • 2,726
  • 1
  • 17
  • 20
  • 1
    Thanks for your answer. So 1 of the biggest reasons to use "await Task.Run((() => "Do Work"));" is that I want to fire off a task that does something and I want to wait for it to complete before I continue next sentence of code. Am I right here ? So will it start only 1 thread when doing "await Task.Run((() => "Do Work"));" or does it start 2 threads ? – syncis Sep 23 '15 at 06:14
  • 1
    That is correct. await means "stop execution right here until my async task finishes" and blocks the calling thread until the async thread is done. I've used this in real life to cache data coming from a web service on application start. The application would fire off 5 asynchronous calls to different services and then await for them all to return before continuing on. This allowed all calls to happen concurrently, but still block until they all completed. Regardless of whether you are using Async/Await or just Task.Run, the task is started on a separate threadpool thread. – DVK Sep 23 '15 at 14:02
  • I see what you were asking regarding the number of threads. Whether you use Task.Run or await it is going to start one thread. Await just basically tells the calling thread to block and monitor the Task thread until it completes. – DVK Sep 23 '15 at 14:15
  • 1
    Simplest answer to my question that I could understood, thank you very much. – syncis Sep 24 '15 at 06:04
  • 13
    @DVK `await` does not block the current thread. async/await as keywords have nothing to do with concurrency. await will simply check to see if the task is completed. if it is, execution proceeds. if it's not, the method returns an unfinished task to the next method up in the call stack. one of the points of async/await is NOT having to block the current thread when waiting for an asynchronous operation to complete. – sara Mar 16 '16 at 13:46
  • @kai Unless you were referring to my comment, I didn't I mention anything about Async/Await blocking the thread. I said the point of using Async/Await is so you can fire an Async task, do something, and then await the task (or many tasks, or whatever). If I remember correctly, if you fail to await an async task, you will get a compiler warning. There are other mechanisms if you don't want to block at any point (eg. Fire and Forget). – DVK Dec 07 '16 at 17:01
  • 10
    @DVK I was refering to your comments where you claimed `await` blocks the current thread, implied that `async`/`await` have anything at all to do with threads, that `await` even spawns threads, etc. All of these are just factually false. – sara Dec 13 '16 at 19:06
  • @DVK - re "I'm going to put this water on to boil, finish prepping the rest of my soup ingredients, and then come back ...". That description runs the risk of someone thinking that `await+async` is sufficient to get *simultaneous* execution. In the context of the question, although the UI thread is not blocked [another UI event could come along and begin executing], the "recipe" you are in the middle of *does not continue until the awaited action completes*. I mean, if `button1_click` had a second statement (prepping ingredients), that would NOT be done while `DoSomething` is running. – ToolmakerSteve Jun 27 '18 at 06:36
18

1

There's a big difference if you don't await the Task or you await it:

  • Case you don't await it: DoSomething is called but next sentence is executed while DoSomething Task hasn't been completed.

  • Case you await it: DoSomething is called and next sentence is executed once DoSomething Task has been completed.

So, the need of async/await will depend on how you want to call DoSomething: if you don't await it is like calling it the fire & forget way.

2

Is it running on the main UI but on a separate thread or is it running on a seperate thread and separate is asynchronously inside that method?

Asynchronous code sometimes means other thread (see this Q&A Asynchronous vs Multithreading - Is there a difference?). That is, either if the code is being executed in a separate thread from the UI one or it lets continue the processing of the UI thread while it gets resumed, it's nice because UI loop can still update the screen while other tasks are being done in parallel without freezing the UI.

An asynchronous method (i.e. async method) is a syntactic sugar to tell the compiler that await statements should be treated as a state machine. The C# compiler turns your async/await code into a state machine where code awaiting a Task result is executed after the code that's being awaited.

Interesting Q&As

You might want to review these other Q&As:

OP said...

[...] But does this mean that "async/await" will fire off a thread and Task.Run also fires off a thread or are they both the same thread?

Using async-await doesn't mean "I create a thread". It's just a syntactic sugar to implement continuations in an elegant way. A Task may or may not be a thread. For example, Task.FromResult(true) creates a fake task to be able to implement an async method without requirement it to create a thread:

public Task<bool> SomeAsync()
{
    // This way, this method either decides if its code is asynchronous or 
    // synchronous, but the caller can await it anyway!
    return Task.FromResult(true);
}
Community
  • 1
  • 1
Matías Fidemraizer
  • 63,804
  • 18
  • 124
  • 206
  • Thanks for your answer. But does this mean that "async/await" will fire off a thread and Task.Run also fires off a thread or are they both the same thread? – syncis Sep 23 '15 at 06:17
  • @syncis async-await doesn't mean "I create a thread". It's just a syntactic sugar to implement continuations in an elegant way. A `Task` can or can't be a thread. For example, `Task.FromResult(true)` creates a *fake* task to be able to implement an async method without requirement it to create a thread. – Matías Fidemraizer Sep 23 '15 at 07:43
  • @syncis Check the update "OP said..." in the answer itself. – Matías Fidemraizer Sep 23 '15 at 07:46
  • 4
    async/await never creates a new thread - it executes the continuation on the same thread it was called from. whether the awaitable method called executes on a new thread async await is oblivious to – markmnl Feb 20 '17 at 06:30
  • 1
    @markmnl So this is what my answer says...See the part of ***OP said***. Excepting about something you are absolutely wrong: async/await never creates a thread BUT it's not true that it always resumes on the same thread when the execution was suspended. – Matías Fidemraizer Feb 20 '17 at 08:22
  • @markmnl BTW, I've fixed another thing in my answer. Asynchronous not always mean *spawning a new thread*. – Matías Fidemraizer Feb 20 '17 at 08:28
  • 1
    @MatíasFidemraizer async await never resumes on a different thread, if the awaitable method spawns a new thread and runs something in the background then returns is of no concern to the caller - the point is when it returns the caller resumes on the same thread that called it. This is the whole point of async await - the caller doesn't have wirte multi-threaded code. – markmnl Feb 21 '17 at 02:17
  • @MatíasFidemraizer perhaps we are saying the same thing, but I find your answer convoluted and confusing.. for instance in the UI example we know the awaited call always resumes on the same thread - the UI thread, otherwise we couldn't use async await from the UI thread unless we were guaranteed once await returns execution continues on the same thread. – markmnl Feb 21 '17 at 02:21
  • @markmnl Is this true for an ASP.NET WebAPI/MVC Core request processing? – Matías Fidemraizer Feb 21 '17 at 04:33
  • 3
    @MatíasFidemraizer I see now not necessarily it depends on the current context, I stand corrected :) http://stackoverflow.com/questions/21838651/i-thought-await-continued-on-the-same-thread-as-the-caller-but-it-seems-not-to – markmnl Feb 22 '17 at 01:46
  • @markmnl Yup, actually I'm not a native desktop/mobile developer, I'm primarly a framework, backend and Web developer. I've worked with both WinForms and WPF but I've been away a long time from them (and probably forever). Really I didn't know that `await` resumed in the UI thread, I understand that you don't need to manually sync another thread with the UI thread anymore, right? – Matías Fidemraizer Feb 22 '17 at 02:18
  • 2
    @markmnl In ASP.NET WebAPI/MVC Core, the fact that `await` resumes on an another thread pool thread is a big advantage, and despite of the simplicity that provides in the UI world (as you've pointed out before), any code with shared resources should be thread-safe by default because otherwise it may work fine in WPF but it can led to a complete disaster in ASP.NET WebAPI. – Matías Fidemraizer Feb 22 '17 at 02:23
  • 1
    @markmnl Conclusion: we need to work with `async`-`await` as if it would never resume on the same thread on which the operation was suspended. – Matías Fidemraizer Feb 22 '17 at 02:24
  • 1
    @MatíasFidemraizer no I wouldn't say that, we can safely assume when on the UI thread it will resume on the UI thread - otherwise we would have to marshal everything back to UI thread.. Also there must be some thread safety synchronisation in the continuation as we don't seem to have to worry about making everything thread-safe in the continuation which we would do if it were just run a on new thread without any synchronization.. – markmnl Mar 02 '17 at 08:23
  • 1
    @markmnl BTW I mean that you wouldn't conclude that it will resume on the caller's thread per se. It depends on context/API. Thus, if a one would ask me that question I would answer: "no, it depends on the `SynchronizationContext`" – Matías Fidemraizer Mar 02 '17 at 10:03
13

The type Task<TResult> requires you to return a TResult from your task. If you don't have anything to return, you can use Task instead (which, incidentally, is the base class of Task<TResult>).

But keep in mind that a task is not a thread. A task is a job to be done, while a thread is a worker. As your program runs, jobs and workers become available and unavailable. Behind the scenes, the library will assign your jobs to available workers and, because creating new workers is a costly operation, it will typically prefer to reuse the existing ones, through a thread pool.

Community
  • 1
  • 1
Theodoros Chatzigiannakis
  • 28,773
  • 8
  • 68
  • 104
  • 1
    Thanks for your answer. But starting a new task on a worker on threadpool, will infact use a thread different from the UI thread. I really cant see any more reasons to use async/await rather than if I want to fire off a task and wait for it to complete before I complete next sentence of code. :/ – syncis Sep 23 '15 at 06:06
  • @syncis and what's the problem with that? – Voo Sep 23 '15 at 11:14
  • One of the true reasons to use `await` is to hide all the ugly boilerplate code normally needed to marshal a result back onto a specific thread (e.g. UI thread). Awaitable tasks have a "synchronization context". If that's the default, then it'll schedule the continuation using the thread pool -- any thread will do. But, if you have a sync context associated with e.g. WPF, and you `await` from the UI thread, then the continuation will get dispatched back to the UI thread automatically. `void button_Click(..) { UIThreadStuff(); await WorkerThreadStuffAsync(); MoreUIThreadStuff(); }` – Jonathan Gilbert Jun 29 '20 at 22:27
  • When we write `await funconeAsync()` or `await Task.Run(funcone)`, then does the funcone run in the UI thread or separate thread? – variable Jul 24 '21 at 08:42
  • @variable when you `await` an `async` method, it will run synchronously until it hits the first `await`. So it depends on if there is code before the first `await` in `funconeAsync()`. If there is code before the first `await`, then `await funconeAsync()` will cause `funconeAsync()` to run synchronously, then the method that is awaited inside `funconeAsync()` will run on a different thread (not UI), BUT the code inside `await funconeAsync()` will only run on the UI thread IF `ConfigureAwait(false)` is not used. `await Task.Run(funcone)` will cause any code inside `funcone` to not run on UI. – David Klempfner Oct 24 '21 at 11:55