Practical example of async await does not meet expectations - c#

Related to this question: Does await completely blocks the thread?
[...] it will first check to see if the called method completed, and if not will register the continuation and return from that method call. Later, once that method completes, it will re-enter the state-machine in order to complete the method
And to this question also: When is the best place to use Task.Result instead of awaiting Task
await simply means "this workflow cannot progress further until this task is completed, so if it is not complete, find more work to do and come back later"
And finally to this post: https://blog.stephencleary.com/2012/02/async-and-await.html
If “await” sees that the awaitable has not completed, then it acts asynchronously. It tells the awaitable to run the remainder of the method when it completes, and then returns from the async method. Later on, when the awaitable completes, it will execute the remainder of the async method. If you’re awaiting a built-in awaitable (such as a task), then the remainder of the async method will execute on a “context” that was captured before the “await” returned.
So from these posts I get that the await operator does indeed not block, but when I've tried to test it i just cannot get this principle to work the way it states to work. Obviously I'm missing something:
//This will take 10 seconds
[HttpGet("test1")]
public async Task<TimeSpan> test()
{
var t1 = DateTime.Now;
var wait1 = DoAsyncEcho("The first!", 10000);
var wait2 = DoAsyncEcho("The second!", 10000);
_logger.LogInformation(await wait1);
_logger.LogInformation(await wait2);
_logger.LogInformation("DONE!");
var t2 = DateTime.Now;
return t2 - t1;
}
//This will take 10 seconds too
[HttpGet("test2")]
public async Task<TimeSpan> test2()
{
var t1 = DateTime.Now;
var wait1 = DoAsyncEcho("The first!", 10000);
var wait2 = DoAsyncEcho("The second!", 10000);
Thread.Sleep(10000);
_logger.LogInformation(await wait1);
_logger.LogInformation(await wait2);
_logger.LogInformation("DONE!");
var t2 = DateTime.Now;
return t2 - t1;
}
//This will take 20
[HttpGet("test3")]
public async Task<TimeSpan> test3()
{
var t1 = DateTime.Now;
var wait1 = await DoAsyncEcho("The first!", 10000);
var wait2 = await DoAsyncEcho("The second!", 10000);
_logger.LogInformation(wait1);
_logger.LogInformation(wait2);
_logger.LogInformation("DONE!");
var t2 = DateTime.Now;
return t2 - t1;
}
//This will take 30
[HttpGet("test4")]
public async Task<TimeSpan> test4()
{
var t1 = DateTime.Now;
var wait1 = await DoAsyncEcho("The first!", 10000);
var wait2 = await DoAsyncEcho("The second!", 10000);
Thread.Sleep(10000);
_logger.LogInformation(wait1);
_logger.LogInformation(wait2);
_logger.LogInformation("DONE!");
var t2 = DateTime.Now;
return t2 - t1;
}
private Task<string> DoAsyncEcho(string v, int t)
{
return Task<string>.Factory.StartNew(() =>
{
Thread.Sleep(t);
return v;
}
);
}
As I see from the methods test3 and test4, await does indeed wait, it does not enter into a state-machine and does a callback later on because it waits the full 10 seconds of the first DoAsyncEcho and then another 10s on the second call. On the methods test1 and test2 execution time lasts for 10s as code does not waits for the return of the DoAsyncEcho but only it awaits for the result later. Particulary test2 method sleeps the 3 calls of 10 seconds in parallel so after all it's just a 10s run.
What do I'm missing here?

I think the best way to demonstrate this is through a simple Windows Forms app.
Create a default Windows Forms app and drop 3 buttons onto it (called button1, button2 and button3.
Then add the following code:
async void button1_Click(object sender, EventArgs e)
{
this.Text = "[button1_Click] About to await slowMethodAsync()";
int result = await slowMethodAsync();
this.Text = "[button1_Click] slowMethodAsync() returned " + result;
}
void button2_Click(object sender, EventArgs e)
{
this.Text = "[button2_Click] About to start task to call slowMethod()";
int result = 0;
Task.Run(() =>
{
result = slowMethod();
}).ContinueWith(_ =>
{
this.Invoke(new Action(() =>
{
this.Text = "[button2_Click] slowMethod() returned " + result;
}));
});
}
void button3_Click(object sender, EventArgs e)
{
this.Text = "[button3_Click] About to call slowMethod()";
int result = slowMethod();
this.Text = "[button3_Click] slowMethod() returned " + result;
}
static async Task<int> slowMethodAsync()
{
await Task.Delay(5000);
return 42;
}
static int slowMethod()
{
Thread.Sleep(5000);
return 42;
}
If you try this code out, you will notice the following:
Pressing button1 will immediately change the title to [button1_Click] About to await Task.Delay(5000), and you can resize the dialog while waiting for 5 seconds, after which the title will change to [button1_Click] Awaited Task.Delay(5000).
The code for handling button2 is very roughly equivalent to the state machine that is generated from the await code for button1. If you press button2, you will see similar effects to pressing button1.
(The actual code for await is in reality quite different, but the underlying mechanism of using a continuation - i.e., ContinueWith() and Invoke(), to continue executing the code after the await on the UI thread illustrates its approach.)
The code for button3 completely blocks during the Thread.Sleep(), and if you press button3 the UI locks up completely for 5 seconds,.
To illustrate what happens with a non-UI example, consider the following console application:
using System;
using System.Threading;
using System.Threading.Tasks;
namespace Demo
{
static class Program
{
static async Task Main()
{
Console.WriteLine("Main thread ID = " + Thread.CurrentThread.ManagedThreadId);
int result = slowMethod();
Console.WriteLine("result = " + result);
Console.WriteLine("After calling slowMethod(), thread ID = " + Thread.CurrentThread.ManagedThreadId);
result = await slowMethodAsync();
Console.WriteLine("result = " + result);
Console.WriteLine("After calling slowMethodAsync(), thread ID = " + Thread.CurrentThread.ManagedThreadId);
}
static async Task<int> slowMethodAsync()
{
await Task.Delay(5000);
return 42;
}
static int slowMethod()
{
Thread.Sleep(5000);
return 42;
}
}
}
If you run that, you will see output similar to the following:
Main thread ID = 1
result = 42
After calling slowMethod(), thread ID = 1
result = 42
After calling slowMethodAsync(), thread ID = 4
Note how the code has resumed on a different thread after the await.
The key thing to realise is that as far as calling code is concerned, y = await X(); does not return until it has a value to return, and the code that runs afterwards may be running on a different thread.
The effect of this in terms of blocking THREADS is that the calling thread is freed up to go off and execute some other code, and another thread is only required when the async method returns.
In many cases, this means that no additional thread is required (for the continuation), and in all cases it means that the original calling thread is not blocked and can be freed up to the thread pool for use for another task.
This is the "non blocking" part of all this.
For a good, detailed explanation of why sometimes no additional thread is needed, read Stephen Cleary's excellent "There is no thread".

It seems that you are confusing two different interpretations of wait and block. The objective of asynchronous code is to block your code, while the thread remains unblocked. If you don't want to block your code, then the solution is easy: don't use await. But if you don't block your code, then you can't use the result of the asynchronous operation, because the asynchronous operation is running concurrently with your code.
What has not happened yet belongs to the future, and the future is unknown. Not only do you not know the result, you don't even know if the operation succeeded or failed. In most cases this is problematic. You need the result of the operation before continuing with processing this result. So you must block your code. And this is why await was invented, to block your code without having to block a thread too.
You need the thread to remain unblocked, so that it continues running the UI message pump that keeps your application responsive. Just because your code is blocked, your _application) need not to be blocked also. For ASP.NET applications, you need the thread to remain unblocked so that it can serve other incoming web requests. The fewer threads you block, the more requests you can serve. In this case async/await becomes a booster of scalability.

Related

Lazy<Task<T>> with asynchronous initialization

class Laziness
{
static string cmdText = null;
static SqlConnection conn = null;
Lazy<Task<Person>> person =
new Lazy<Task<Person>>(async () =>
{
using (var cmd = new SqlCommand(cmdText, conn))
using (var reader = await cmd.ExecuteReaderAsync())
{
if (await reader.ReadAsync())
{
string firstName = reader["first_name"].ToString();
string lastName = reader["last_name"].ToString();
return new Person(firstName, lastName);
}
}
throw new Exception("Failed to fetch Person");
});
public async Task<Person> FetchPerson()
{
return await person.Value;
}
}
And the book, "Concurrency in .NET" by Riccardo Terrell, June 2018, says:
But there's a subtle risk. Because Lambda expression is asynchronous,
it can be executed on any thread that calls Value and the expression
will run within the context. A better solution is to wrap the
expression in an underlying Task which will force the asynchronous
execution on a thread pool thread.
I don't see what's the risk from the current code ?
Is it to prevent deadlock in case the code is run on the UI thread and is explicity waited like that:
new Laziness().FetchPerson().Wait();
I don't see what's the risk from the current code ?
To me, the primary issue is that the asynchronous initialization delegate doesn't know what context/thread it'll run on, and that the context/thread could be different based on a race condition. For example, if a UI thread and a thread pool thread both attempt to access Value at the same time, in some executions the delegate will be run in a UI context and in others it will be run in a thread pool context. In the ASP.NET (pre-Core) world, it can get a bit trickier: it's possible for the delegate to capture a request context for a request that is then canceled (and disposed), and attempt to resume on that context, which isn't pretty.
Most of the time, it wouldn't matter. But there are these cases where Bad Things can happen. Introducing a Task.Run just removes this uncertainty: the delegate will always run without a context on a thread pool thread.
I simplified your example to show what happens in each case. In the first case the Task is created using an async lambda:
Lazy<Task<string>> myLazy = new Lazy<Task<string>>(async () =>
{
string result = $"Before Delay: #{Thread.CurrentThread.ManagedThreadId}";
await Task.Delay(100);
return result += $", After Delay: #{Thread.CurrentThread.ManagedThreadId}";
});
private async void Button1_Click(object sender, EventArgs e)
{
int t1 = Thread.CurrentThread.ManagedThreadId;
var result = await myLazy.Value;
int t2 = Thread.CurrentThread.ManagedThreadId;
MessageBox.Show($"Before await: #{t1}, {result}, After await: #{t2}");
}
I embedded this code in a new Windows Forms application with a single button, and on clicking the button this message popped up:
Before await: #1, Before Delay: #1, After Delay: #1, After await: #1
Then I changed the valueFactory argument to use Task.Run instead:
Lazy<Task<string>> myLazy = new Lazy<Task<string>>(() => Task.Run(async () =>
{
string result = $"Before Delay: #{Thread.CurrentThread.ManagedThreadId}";
await Task.Delay(100);
return result += $", After Delay: #{Thread.CurrentThread.ManagedThreadId}";
}));
Now the message is this:
Before await: #1, Before Delay: #3, After Delay: #4, After await: #1
So not using Task.Run means that your code before, between and after the awaits will run on the UI thread. Which might not be a big deal, unless there is CPU intensive or IO blocking code hidden somewhere. For example the constructor of the Person class, as innocent as it might look, could contain some call to a database or web API. By using Task.Run you can be sure that the initialization of the Lazy class will not touch the UI thread before it's done.

What is difference between async await and invoking wait? [duplicate]

I may be missing something but what is the difference between doing:
public void MyMethod()
{
Task t = Task.Factory.StartNew(DoSomethingThatTakesTime);
t.Wait();
UpdateLabelToSayItsComplete();
}
public async void MyMethod()
{
var result = Task.Factory.StartNew(DoSomethingThatTakesTime);
await result;
UpdateLabelToSayItsComplete();
}
private void DoSomethingThatTakesTime()
{
Thread.Sleep(10000);
}
I may be missing something
You are.
what is the difference between doing Task.Wait and await task?
You order your lunch from the waiter at the restaurant. A moment after giving your order, a friend walks in and sits down next to you and starts a conversation. Now you have two choices. You can ignore your friend until the task is complete -- you can wait until your soup arrives and do nothing else while you are waiting. Or you can respond to your friend, and when your friend stops talking, the waiter will bring you your soup.
Task.Wait blocks until the task is complete -- you ignore your friend until the task is complete. await keeps processing messages in the message queue, and when the task is complete, it enqueues a message that says "pick up where you left off after that await". You talk to your friend, and when there is a break in the conversation the soup arrives.
To demonstrate Eric's answer here is some code:
public void ButtonClick(object sender, EventArgs e)
{
Task t = new Task.Factory.StartNew(DoSomethingThatTakesTime);
t.Wait();
//If you press Button2 now you won't see anything in the console
//until this task is complete and then the label will be updated!
UpdateLabelToSayItsComplete();
}
public async void ButtonClick(object sender, EventArgs e)
{
var result = Task.Factory.StartNew(DoSomethingThatTakesTime);
await result;
//If you press Button2 now you will see stuff in the console and
//when the long method returns it will update the label!
UpdateLabelToSayItsComplete();
}
public void Button_2_Click(object sender, EventArgs e)
{
Console.WriteLine("Button 2 Clicked");
}
private void DoSomethingThatTakesTime()
{
Thread.Sleep(10000);
}
This example demonstrates the difference very clearly. With async/await the calling thread will not block and continue executing.
static void Main(string[] args)
{
WriteOutput("Program Begin");
// DoAsTask();
DoAsAsync();
WriteOutput("Program End");
Console.ReadLine();
}
static void DoAsTask()
{
WriteOutput("1 - Starting");
var t = Task.Factory.StartNew<int>(DoSomethingThatTakesTime);
WriteOutput("2 - Task started");
t.Wait();
WriteOutput("3 - Task completed with result: " + t.Result);
}
static async Task DoAsAsync()
{
WriteOutput("1 - Starting");
var t = Task.Factory.StartNew<int>(DoSomethingThatTakesTime);
WriteOutput("2 - Task started");
var result = await t;
WriteOutput("3 - Task completed with result: " + result);
}
static int DoSomethingThatTakesTime()
{
WriteOutput("A - Started something");
Thread.Sleep(1000);
WriteOutput("B - Completed something");
return 123;
}
static void WriteOutput(string message)
{
Console.WriteLine("[{0}] {1}", Thread.CurrentThread.ManagedThreadId, message);
}
DoAsTask Output:
[1] Program Begin
[1] 1 - Starting
[1] 2 - Task started
[3] A - Started something
[3] B - Completed something
[1] 3 - Task completed with result: 123
[1] Program End
DoAsAsync Output:
[1] Program Begin
[1] 1 - Starting
[1] 2 - Task started
[3] A - Started something
[1] Program End
[3] B - Completed something
[3] 3 - Task completed with result: 123
Update: Improved example by showing the thread ID in the output.
Wait(), will cause to run potentially async code in sync manner. await will not.
For example, you have an asp.net web application. UserA calls /getUser/1 endpoint. asp.net app pool will pick a thread from thread pool (Thread1) and, this thread will make a http call. If you do Wait(), this thread will be blocked until http call resolves. While it is waiting, if UserB calls /getUser/2, then, app pool will need to serve another thread (Thread2) to make http call again. You just created (Well, fetched from app pool actually) another thread for no reason, because you cannot use Thread1 it was blocked by Wait().
If you use await on Thread1, then, SyncContext will manage sync between Thread1 and http call. Simply, it will notify once http call is done. Meanwhile, if UserB calls /getUser/2, then, you will use Thread1 again to make http call, because it was released once await got hit. Then another request can use it, even further more. Once http call is done (user1 or user2), Thread1 can get the result and return to caller (client). Thread1 was used for multiple tasks.
In this example, not much, practically. If you are awaiting a Task that returns on a different thread (like a WCF call) or relinquishes control to the operating system (like File IO), await will use fewer system resources by not blocking a thread.
In the example above, you can use "TaskCreationOptions.HideScheduler", and greatly modify the "DoAsTask" method. The method itself is not asynchronous, as it happens with "DoAsAsync" because it returns a "Task" value and is marked as "async", making several combinations, this is how it gives me exactly the same as using "async / await":
static Task DoAsTask()
{
WriteOutput("1 - Starting");
var t = Task.Factory.StartNew<int>(DoSomethingThatTakesTime, TaskCreationOptions.HideScheduler); //<-- HideScheduler do the magic
TaskCompletionSource<int> tsc = new TaskCompletionSource<int>();
t.ContinueWith(tsk => tsc.TrySetResult(tsk.Result)); //<-- Set the result to the created Task
WriteOutput("2 - Task started");
tsc.Task.ContinueWith(tsk => WriteOutput("3 - Task completed with result: " + tsk.Result)); //<-- Complete the Task
return tsc.Task;
}

Async/Await action within Task.Run()

Task.Run(()=>{}) puts the action delegate into the queue and returns the task .
Is there any benefit of having async/await within the Task.Run()?
I understand that Task.Run() is required since if we want to use await directly, then the calling method will need to be made Async and will affect the calling places.
Here is the sample code which has async await within Task.Run(). The full sample is provided here: Create pre-computed tasks.
Task.Run(async () => { await new WebClient().DownloadStringTaskAsync("");});
Alternatively this could have been done:
Task.Run(() => new WebClient().DownloadStringTaskAsync("").Result;);
Since both, Task.Run() and Await will queue the work and will be picked by the thread pool, could the async/await within the Task.Run() be a bit redundant?
Is there any benefit of having async/await within the Task.Run() ?
Yes. Task.Run runs some action on a thread-pool thread. If such action does some IO work and asynchronously waits for the IO operation to complete via await, then this thread-pool thread can be used by the system for other work while the IO operation is still running.
Example:
Task.Run( async () =>
{
DoSomeCPUIntensiveWork();
// While asynchronously waiting for this to complete,
// the thread is given back to the thread-pool
var io_result = await DoSomeIOOperation();
DoSomeOtherCPUIntensiveWork(io_result);
});
Is there any benefit of having async/await within the Task.Run()
An async method returns to the caller as soon as the first await is hit (that operates on a non-completed task). So if that first execution "streak" of an async method takes a long time Task.Run will alter behavior: It will cause the method to immediately return and execute that first "streak" on the thread-pool.
This is useful in UI scenarios because that way you can make 100% sure that you are not blocking the UI. Example: HttpWebRequestdoes DNS resolution synchronously even when you use one of the async methods (this is basically a library bug/design error). This can pause the UI thread. So you can use Task.Run to be 100% sure that the UI is never blocked for longer than a few microseconds.
So back to the original question: Why await inside a Task.Run body? For the same reason you normally await: To unblock the thread.
In the example that you linked the main thread is being blocked until the asynchronous operation is done. It's being blocked by calling Wait() (which by the way is generally a bad idea).
Let's have a look at the return from the DownloadStringAsync in the linked sample:
return Task.Run(async () =>
{
content = await new WebClient().DownloadStringTaskAsync(address);
cachedDownloads.TryAdd(address, content);
return content;
});
Why would you wrap this in a Task? Think about your options for a second. If you don't want to wrap this in a Task, how would you make sure the method returns a Task<string> and still have it work? You'd mark the method as async of course! However, if you mark your method as async and you call Wait on it, you'll most likely end up with a deadlock, since the main thread is waiting for the work to finish, and your blocking the main thread so it can't let you know it's done.
When marking a method as async, the state machine will run on the calling thread, in your example however, the state machine runs on a separate thread, meaning there is little to no work being done on the main thread.
Calling Async from Non-Async Methods
We do some stuff like that when we are trying to call an async method inside of a non-async method. Especially if the async method is a known quantity. We use more of a TaskFactory though ... fits a pattern, makes it easier to debug, makes sure everyone takes the same approach (and -- gives us one throat to choke if async-->sync starts acting buggy).
So, Your Example
Imagine, in your example, that you have a non-async function. And, within that function, you need to call await webClient.DoSomethingAsync(). You can't call await inside of a function that's not async -- the compiler won't let you.
Option 1: Zombie Infestation
Your first option is to crawl all the way back up your call stack, marking every da*n method along the way as async and adding awaits everywhere. Everywhere. Like, everywhere. Then -- since all those methods are now async, you need to make the methods that reference them all async.
This, btw, is probably the approach many of the SO enthusiasts are going to advocate. Because, "blocking a thread is a bad idea."
So. Yeah. This "let async be async" approach means your little library routine to get a json object just reached out and touched 80% of the code. Who's going to call the CTO and let him know?
Option 2: Just Go with the One Zombie
OR, you can encapsulate your async inside of some function like yours...
return Task.Run(async () => {
content = await new WebClient().DoSomethingAsync();
cachedDownloads.TryAdd(address, content);
return content;
});
Presto... the zombie infestation has been contained to a single section of code. I'll leave it to the bit-mechanics to argue over how/why that gets executed at the CPU-level. I don't really care. I care that nobody has to explain to the CTO why the entire library should now be 100% async (or something like that).
Confirmed, wrapping await with Task.Run use 2 threads instead of one.
Task.Run(async () => { //thread #1
await new WebClient().DownloadStringTaskAsync(""); //thread #2
});
Say you have four calls wrapped like this, it will use 4 x 2 = 8 threads.
It would be better to just call these with simple await instead. For example:
Task<byte[]> t1 = new WebClient().DownloadStringTaskAsync("");
Task<byte[]> t2 = new WebClient().DownloadStringTaskAsync("");
byte[] t1Result = await t1;
byte[] t2Result = await t2;
Here is the proof that wrapped Task.Run are using extra threads. (Not using WebClient to prove the point)
private static async Task wrapped()
{
List<Task> tasks = new List<Task>();
tasks.AddRange(new []
{
Task.Run(async() => await new MyThread().RunMe()),
Task.Run(async() => await new MyThread().RunMe()),
Task.Run(async() => await new MyThread().RunMe()),
Task.Run(async() => await new MyThread().RunMe()),
});
Thread.Sleep(1000);
int number = Process.GetCurrentProcess().Threads.Count;
Console.WriteLine($"While running thread count: {number}");
await Task.WhenAll(tasks);
}
Unwrapped
private static async Task unwrapped()
{
List<Task> tasks = new List<Task>();
Task<int> t1 = new MyThread().RunMe();
Task<int> t2 = new MyThread().RunMe();
Task<int> t3 = new MyThread().RunMe();
Task<int> t4 = new MyThread().RunMe();
tasks.AddRange(new[] {t1, t2, t3, t4});
Thread.Sleep(1000);
int number = Process.GetCurrentProcess().Threads.Count;
Console.WriteLine($"While running thread count: {number}");
int i1 = await t1;
int i2 = await t2;
int i3 = await t3;
int i4 = await t4;
}
Full POC code here
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
namespace AsyncThreadDemo
{
class Program
{
static async Task Main(string[] args)
{
int number = Process.GetCurrentProcess().Threads.Count;
Console.WriteLine($"Init thread count: {number}");
//await wrapped();
await unwrapped();
number = Process.GetCurrentProcess().Threads.Count;
Console.WriteLine($"Done thread count: {number}");
Console.ReadLine();
}
private static async Task wrapped()
{
List<Task> tasks = new List<Task>();
tasks.AddRange(new []
{
Task.Run(async() => await new MyThread().RunMe()),
Task.Run(async() => await new MyThread().RunMe()),
Task.Run(async() => await new MyThread().RunMe()),
Task.Run(async() => await new MyThread().RunMe()),
});
Thread.Sleep(1000);
int number = Process.GetCurrentProcess().Threads.Count;
Console.WriteLine($"While running thread count: {number}");
await Task.WhenAll(tasks);
}
private static async Task unwrapped()
{
List<Task> tasks = new List<Task>();
Task<int> t1 = new MyThread().RunMe();
Task<int> t2 = new MyThread().RunMe();
Task<int> t3 = new MyThread().RunMe();
Task<int> t4 = new MyThread().RunMe();
tasks.AddRange(new[] {t1, t2, t3, t4});
Thread.Sleep(1000);
int number = Process.GetCurrentProcess().Threads.Count;
Console.WriteLine($"While running thread count: {number}");
int i1 = await t1;
int i2 = await t2;
int i3 = await t3;
int i4 = await t4;
}
}
public class MyThread
{
public static int _counter;
public async Task<int> RunMe()
{
await Task.Run(() =>
{
for (int i = 0; i < 2; ++i)
{
Thread.Sleep(1000);
Console.WriteLine($"T{Thread.CurrentThread.ManagedThreadId} {i}");
}
Console.WriteLine($"T{Thread.CurrentThread.ManagedThreadId} done");
});
return _counter++;
}
}
}

WPF ProgressBar usage when using Async/Await

I have a very simple task that loads some data like so:
async Task<List<Invoice>> GetInvoices()
{
var invoices = await Task.Run(() => db.Invoices.AsNoTracking().ToList());
return invoices;
}
What would be the best way to use this with a progressbar? I don't need to get the percentage loaded (although that would be useful), I simply need to show/hide the progressbar at start and finish of loading data. Is there a way to create a completed or finished method perhaps?
I am very new to async/await so kid gloves please!
Assuming GetInvoices gets called in some UI event handler and there is some progress bar control called ProgressBar, it's really simple:
private async void OnButton1Click(..)
{
ProgressBar.IsIndeterminate = true;
var result = await GetInvoices();
ProgressBar.IsIndeterminate = false; // Maybe hide it, too
// TODO: Do stuff with result
}
If you want to show actual progress, take a look at Progress<T> and IProgress<T>.
You already have what you need. To illustrate here's a simple example with tasks and using await, and ContinueWith.
using System;
using System.Threading.Tasks;
using System.Diagnostics;
public class Program
{
public static void Main()
{
Task t = new Program().TestTasks();
Console.WriteLine("hello");
t.Wait();
}
public async Task TestTasks()
{
Stopwatch watch = Stopwatch.StartNew();
Console.WriteLine("1." + watch.ElapsedMilliseconds);
// await task
int res = await TestAsync();
Console.WriteLine("2." + watch.ElapsedMilliseconds + " " + res);
// save task and wait on it
Task<int> t = TestAsync();
t.ContinueWith((r) =>
{
Console.WriteLine("4." + watch.ElapsedMilliseconds + " " + r.Result);
});
Console.WriteLine("3." + watch.ElapsedMilliseconds);
t.Wait();
}
public static async Task<int> TestAsync()
{
await Task.Delay(TimeSpan.FromSeconds(2));
return 42;
}
}
This prints:
1.0
hello
2.2009 42
3.2009
4.4013 42
Note how the await leaves the method and prints "hello" in the Main method, and after (about) 2 seconds continue in the TestTasks method. On the other hand, if we do not await, as the second call to TestAsync shows, 3. is printed immediately, and after 2 seconds, 4. is printed.
With this in mind, you can just call your method GetInvoices with await since you're returning a Task.
// Set state of progressbar to indeterminate
List<Invoice> result = await GetInvoices();
// Set state of progressbar to nothing
You can do something like:
var task = Task.Run(() => db.Invoices.AsNoTracking().ToList());
//show progress
task.ContinueWith(...CLOSE PROGRESS BAR...);
In practise you use Task.ContinueWith construct to catch the termination of the task and hide a progress bar you have shown before.
Note: keep in mind that acting on UI element from another thread requires Invoke() call, as that call redirects actual invokation to the main thread, which is a only thread were UI controls can be operated on windows.

Can the last await be replaced with an explicit wait?

I'm still learning the async/await, so please excuse me if I'm asking something obvious. Consider the following example:
class Program {
static void Main(string[] args) {
var result = FooAsync().Result;
Console.WriteLine(result);
}
static async Task<int> FooAsync() {
var t1 = Method1Async();
var t2 = Method2Async();
var result1 = await t1;
var result2 = await t2;
return result1 + result2;
}
static Task<int> Method1Async() {
return Task.Run(
() => {
Thread.Sleep(1000);
return 11;
}
);
}
static Task<int> Method2Async() {
return Task.Run(
() => {
Thread.Sleep(1000);
return 22;
}
);
}
}
This behaves as expected and prints "33" in the console.
If I replace the second await with an explicit wait...
static async Task<int> FooAsync() {
var t1 = Method1Async();
var t2 = Method2Async();
var result1 = await t1;
var result2 = t2.Result;
return result1 + result2;
}
...I seem to get the same behavior.
Are these two examples completely equivalent?
And if they are equivalent in this case, are there any other cases where replacing the last await by an explicit wait would make a difference?
Your replacement version blocks the calling thread waiting for the task to finish. It's hard to see a visible difference in a console app like that since you're intentionally blocking in Main, but they're definitely not equivalent.
They are not equivalent.
Task.Result blocks until the result is available. As I explain on my blog, this can cause deadlocks if you have an async context that requires exclusive access (e.g., a UI or ASP.NET app).
Also, Task.Result will wrap any exceptions in AggregateException, so error handling is harder if you synchronously block.
OK, I think I figured this out so let me sum it up, in what will hopefully be a more complete explanation than the answers provided so far...
Short Answer
Replacing the second await with an explicit wait will have no appreciable effect on a console application, but will block the UI thread of a WPF or WinForms application for the duration of the wait.
Also, the exception handling is slightly different (as noted by Stephen Cleary).
Long Answer
In a nutshell, the await does this:
If the awaited task has already finished, it just retrieves its result and continues.
If it hasn't, it posts the continuation (the rest of the method after the await) to the current synchronization context, if there is one. Essentially, await is trying to return us where we started from.
If there isn't a current context, it just uses the original TaskScheduler, which is usually thread pool.
The second (and third and so on...) await does the same.
Since the console applications typically have no synchronization context, continuations will typically be handled by the thread pool, so there is no issue if we block within the continuation.
WinForms or WPF, on the other hand, have synchronization context implemented on top of their message loop. Therefore, await executed on a UI thread will (eventually) execute its continuation on the UI thread as well. If we happen to block in the continuation, it will block the message loop and make the UI non-responsive until we unblock. OTOH, if we just await, it will neatly post continuations to be eventually executed on the UI thread, without ever blocking the UI thread.
In the following WinForms form, containing one button and one label, using await keeps the UI responsive at all times (note the async in front of the click handler):
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
}
private async void button1_Click(object sender, EventArgs e) {
var result = await FooAsync();
label1.Text = result.ToString();
}
static async Task<int> FooAsync() {
var t1 = Method1Async();
var t2 = Method2Async();
var result1 = await t1;
var result2 = await t2;
return result1 + result2;
}
static Task<int> Method1Async() {
return Task.Run(
() => {
Thread.Sleep(3000);
return 11;
}
);
}
static Task<int> Method2Async() {
return Task.Run(
() => {
Thread.Sleep(5000);
return 22;
}
);
}
}
If we replaced the second await in FooAsync with t2.Result, it would continue to be responsive for about 3 seconds after the button click, and then freeze for about 2 seconds:
The continuation after the first await will politely wait its turn to be scheduled on the UI thread, which would happen after Method1Async() task finishes, i.e. after about 3 seconds,
at which point the t2.Result will rudely block the UI thread until the Method2Async() task finishes, about 2 seconds later.
If we removed the async in front of the button1_Click and replaced its await with FooAsync().Result it would deadlock:
The UI thread would wait on FooAsync() task to finish,
which would wait on its continuation to finish,
which would wait on the UI thread to become available,
which it isn't, since it is blocked by the FooAsync().Result.
The article "Await, SynchronizationContext, and Console Apps" by Stephen Toub was invaluable to me in understanding this subject.

Categories