When correctly use Task.Run and when just async-await
Note the guidelines for performing work on a UI thread, collected on my blog:
- Don't block the UI thread for more than 50ms at a time.
- You can schedule ~100 continuations on the UI thread per second; 1000 is too much.
There are two techniques you should use:
1) Use ConfigureAwait(false)
when you can.
E.g., await MyAsync().ConfigureAwait(false);
instead of await MyAsync();
.
ConfigureAwait(false)
tells the await
that you do not need to resume on the current context (in this case, "on the current context" means "on the UI thread"). However, for the rest of that async
method (after the ConfigureAwait
), you cannot do anything that assumes you're in the current context (e.g., update UI elements).
For more information, see my MSDN article Best Practices in Asynchronous Programming.
2) Use Task.Run
to call CPU-bound methods.
You should use Task.Run
, but not within any code you want to be reusable (i.e., library code). So you use Task.Run
to call the method, not as part of the implementation of the method.
So purely CPU-bound work would look like this:
// Documentation: This method is CPU-bound.
void DoWork();
Which you would call using Task.Run
:
await Task.Run(() => DoWork());
Methods that are a mixture of CPU-bound and I/O-bound should have an Async
signature with documentation pointing out their CPU-bound nature:
// Documentation: This method is CPU-bound.
Task DoWorkAsync();
Which you would also call using Task.Run
(since it is partially CPU-bound):
await Task.Run(() => DoWorkAsync());
what's the benefit of running async code with task.run()
With the 2nd option, the work is already being offloaded to a separate thread, then the asynchronicity is already gained in the scope of the program that invoked t2.
Task.Run
doesn't make something asynchronous. It does permit you to run synchronous code on a thread pool thread (and thus blocking a thread pool thread instead of some other thread), but I wouldn't say it "makes it asynchronous". The code is still blocking a thread, synchronously.
Now although the work that is being done in the 1st option is declared and implemented as async, it's essentially letting code that is already being ran asynchronously, to also run itself asynchronously. What benefits from it ? Can the the scheduler or whatever manages those task threads read into this? and then perhaps give that awaiting thread some work on another task ?
Threads don't await
. Methods await
. When a thread is running a method and hits an await
, that method is paused, the method returns to its caller, and the thread continues executing. In the case of a delegate passed to Task.Run
, the await
will cause the method to return -- to the thread pool, thus returning the thread to the thread pool. When the await
ed task completes, a thread from the thread pool will be used to resume executing the method; this may be the same thread or a completely different thread.
More info on how exactly await
works is on my blog.
if this is the case I haven't seen it mentioned in any expert blog post, or relevant page on the internet.
I have a series on Task.Run
etiquette. Essentially, Task.Run
is primarily used to offload synchronous or CPU-bound work off the UI thread in GUI applications. It is also occasionally useful in server-side scenarios if you want to start something processing quickly and loop back around and grab the next thing to process. There are a few other use cases but they are rare.
These reasons can all hold for asynchronous APIs. Sometimes APIs appear asynchronous but aren't actually. Or some methods are asynchronous but they do a nontrivial amount of synchronous work first, so a Task.Run
is still desirable in some cases even with asynchronous code.
Is using Task.Run a short hand for async await?
I'm not sure the title of your question totally matches the actual question you're asking in the body, so I'll go with the body:
There's at least one really big difference between your two examples. With this (Option 1):
Task.Run(fn1sync());
Task.Run(fn2sync());
you have no way of waiting for both tasks to finish. They will run in parallel (PROBABLY - but not guaranteed - in different threads). They will both begin immediately and finish when they finish. Any code after that will also execute immediately, without waiting for the tasks to finish.
With this (Option 2):
var v1 = fn1Async()
var v2 = fn2Async()
...do some work..
Task.WaitAll(v1, v2)
You're holding onto the tasks and then after "do some work", you're explicitly waiting for both to finish before continuing. Nothing after the last line will execute until both are finished.
The question becomes more interesting - and maybe this is what you were getting at? - if you re-write option 1 this way (let's call it Option 3):
var v1 = Task.Run(fn1sync());
var v2 = Task.Run(fn2sync());
...do some work...
Task.WaitAll(v1, v2);
Are Option 2 and Option 3 identical? The answer is still no.
When you call an async method/delegate/etc. without awaiting it, which is what option 2 does, whether the delegate actually finishes before the calling branch can continue depends on whether the delegate invokes any truly async code. For example you could write this method:
public Task fn1sync()
{
Console.Write("Task complete!");
return Task.CompletedTask;
}
The Console.Write
line will always execute before "do some work". Why? Because if you think of the return object Task
literally, then fn1sync
by definition can't be returning a Task
to your calling code before it writes to the console (which is a synchronous operation). Replace "Console.Write" with something really slow, or maybe even blocking, and you've lost the benefits of async.
When you use Task.Run
, on the other hand, you guarantee that the control flow will return to your next line of code immediately, no matter how long the delegate takes to execute and regardless whether the delegate actually contains any async code. You thus ensure that your calling thread won't get slowed down by whatever is in the delegate. In fact it's a great idea to use Task.Run
when you have to invoke synchronous code that you have any reason to believe is going to be slow - legacy I/O, databases, native code, etc.
The use cases for calling an async
method without awaiting it or wrapping it in Task.Run
(Option 2) are perhaps less obvious but they do exist. It's a "fire and forget" approach that's fine as long as you know the code you're calling is well behaved async code (i.e. it's not going to block your thread). For example if fn1Async
in Option 2 looked like this:
public Task fn1sync()
{
return Task.Run(()=>
{
Console.Write("Task complete!");
});
}
Then Options 2 and 3 would be fully equivalent and equally valid.
Update: To answer your question, "Can you tell me why does await in main thread cause it to block waiting for result, whereas await inside a function results in control passing to main thread?"
I agree with some of the comments that you might want to find a more comprehensive primer on async/await/Task. But that said, it's all about branching and how the await
keyword is interpreted when it's compiled.
When you write:
async Task MyMethodAsync()
{
Console.Write("A");
int result = await AnotherMethodAsync();
Console.Write("B");
return;
}
This basically gets converted to:
Task MyMethodAsync()
{
Console.Write("A");
Task<int> task1 = AnotherMethodAsync(); // *should* return immediately if well behaved
Task task2 = task1.ContinueWith((Task<int> t) =>
{
// t is same as task1 (unsure if they're identical instances but definitely equivalent)
int result = t.Value;
Console.Write("B");
return;
}); // returns immediately
return task2;
}
Everything before the first await
ed statement in a method executes synchronously - on the caller's thread. But everything after the first awaited statement becomes a callback that gets executed only after the first awaited statement - task1
- is finished.
Importantly, ContinueWith
returns its own Task
- task2
and THAT is what is is returned to the caller of MyMethodAsync
, allowing them to await
it or not as they choose. The line "Console.Write("B")
is guaranteed not to get executed until task1
is complete. However, when it gets executed relative to the code that follows the call to MyMethodAsync
depends entirely on whether that call is await
ed.
Thus:
async Task Main()
{
await MyMethodAsync();
Console.Write("C");
}
becomes:
Task Main()
{
return MyMethodAsync().ContinueWith(t =>
{
// Doesn't get executed until MyMethodAsync is done
Console.Write("C");
});
}
and the output is thus guaranteed to be: ABC
However:
void Main()
{
Task t = MyMethodAsync(); // Returns after "A" is written
// Gets executed as soon as MyMethodAsync
// branches to `await`ed code, returning the `Task`
// May or may not be before "B"
Console.Write("C");
}
executes literally, with t
getting returned in an incomplete state, after "A" but before "C". The output is thus guaranteed to start with "A" but whether "B" or "C" will come next will not be predictable without knowing what AnotherMethodAsync
is doing.
Understanding async / await and Task.Run()
It's as simple as you not awaiting the Task.Run, so the exception gets eaten and not returned to the call site of Task.Run.
Add "await" in front of the Task.Run, and you'll get the exception.
This will not crash your application:
private void button1_Click(object sender, EventArgs e)
{
Task.Run(() => { throw new Exception("Hello");});
}
This however will crash your application:
private async void button1_Click(object sender, EventArgs e)
{
await Task.Run(() => { throw new Exception("Hello");});
}
await Task.Run vs await
Task.Run
may post the operation to be processed at a different thread. That's the only difference.
This may be of use - for example, if LongProcess
isn't truly asynchronous, it will make the caller return faster. But for a truly asynchronous method, there's no point in using Task.Run
, and it may result in unnecessary waste.
Be careful, though, because the behaviour of Task.Run
will change based on overload resolution. In your example, the Func<Task>
overload will be chosen, which will (correctly) wait for LongProcess
to finish. However, if a non-task-returning delegate was used, Task.Run
will only wait for execution up to the first await
(note that this is how TaskFactory.StartNew
will always behave, so don't use that).
asyn await vs await task.run
The difference is in the context in which the code will be run. return "Good Job";
will be executed instantly in the separate task (and possibly on the separate thread - this is determined by the default task scheduler, like ThreadPool
). In the second one, all code in GetMessage before the first await will be executed synchronously, in the same context as the caller. The rest of the code after await
will be delegated to the separate task.
When to use Task.Run, when to use async- await and when to use them in combination
When to use Task.Run, when to use async- await and when to use them in combination
I have an entire blog series on the subject, but in summary:
- Use
Task.Run
to move CPU-bound (or blocking) work off of the UI thread for apps with a UI. - Use
async
/await
for I/O-bound work.
There are some more rare cases where Task.Run
or async
can be useful, but the two points above provide guidance for most situations.
Does Task.Run means background thread will behave as a blocking thread?
Task.Run
can actually run synchronously or asynchronously, but it does use thread pool threads.
i am trying to create a desktop console application in .net 4.5
Trying to download multiple large images from internet. How should i use these keywords in combination and why?
This is an I/O-bound operation in a non-UI app, so you should definitely prefer async
/await
.
Related Topics
How to Create a Dropdownlist from an Enum in ASP.NET MVC
How to Generate Random Alphanumeric Strings
How to Fix the Flickering in User Controls
Why Is Floating Point Arithmetic in C# Imprecise
How Would You Count Occurrences of a String (Actually a Char) Within a String
One Dbcontext Per Web Request... Why
Capture Screenshot of Active Window
Await' Works, But Calling Task.Result Hangs/Deadlocks
Convert Generic List/Enumerable to Datatable
How to Make the Script Wait/Sleep in a Simple Way in Unity
Direct Casting VS 'As' Operator
Proper Use of the Idisposable Interface
Cannot Convert from List≪Derivedclass≫ to List≪Baseclass≫