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.
Related
I'm trying to chain tasks, so as soon as the one finishes the next starts, but the UI doesn't update. I did a course in react and the one lesson is where you update the UI based on state changes in the application, and that is what I'm trying to replicate. Change the state of the application (basically I'll be running methods that run return a bool for validation), and then update the UI accordingly, I'm also using binding, but for some reason its not running as intended, I don't know if I follow the documentation incorrectly. What can I change or fix to make this work and is it practically correct to use more than one task in a single async Task<T> method
public async Task<string> Connect_To_Ip()
{
await Task.Run(() =>
{
details.State = "Connection To IP 127.0.01.258.....";
Task.Delay(5000).Wait();
}).ContinueWith(result => new Task(async () =>
{
await Task.Run(() =>
{
if (result.Status == TaskStatus.RanToCompletion)
{
details.State = "Validating Card Number......";
}
});
}), TaskContinuationOptions.OnlyOnRanToCompletion);
return details.State;
}
How I'm calling the original task
Task connect = Connect_To_Ip();
await connect;
When you use await then you don't need Task.ContinueWith. Everything that follows the awaited operation is a continuation. Since you want to validate on a background thread, you must post the changes back to the UI thread in order to update the UI elements, otherwise you will produce cross-thread exceptions.
This is because UI elements can't be updated from a background thread, except the update occurs via INotifyPropertyChanged and data binding.
One way to do this is to use the Dispatcher to invoke UI manipulations on the UI thread or use the Progress<T> class, which will always execute the registered callback on the UI thread.
Your fixed and simplified code could look like this example:
public async Task ValidateAsync()
{
// Register the callback that updates the UI with the 'progressReporter'.
// Progress<T> must be instantiated on the UI thread it is associated with
var progressReporter = new Progress<string>(message => details.State = message);
// Execute the operation on a background thread
await Task.Run(() => ConnectToIp(progressReporter));
// Continuation starts here, after await
}
public async Task ConnectToIp(IProgress<string> progressReporter)
{
progressReporter.Report("Connection To IP 127.0.01.258.....");
await Task.Delay(TimeSpan.FromSeconds(5));
// Continuation starts here, after await
progressReporter.Report("Validating Card Number......");
}
It is recommended to use async APIs when possible instead of using background threads. For example, to connect to a server without blocking the UI you can use
HttpClient client = new HttpClient();
HttpResponseMessage response = await client.GetAsync("http://www.contoso.com/");
Many IO classes provide an async API.
Furthermore, I recommend to take a look at the INotifyDataErrorInfo interface. It is the recommended way to implement property validation and allows to provide UI error feedback in a very easy way.
I did this in Windows Forms (I had a test Windows Forms project open), but it should be about the same in WPF. I dropped a button, a label and a text box on the form. Then I wrote this code:
private async void button1_Click(object sender, EventArgs e)
{
var result = await ValidateTextBox();
if (result != null)
{
label1.Text = result;
return;
}
var intResult = await ReadTextBox();
label1.Text = intResult.ToString();
await IncrementTextBox();
intResult = await ReadTextBox();
label1.Text = intResult.ToString();
}
private async Task<string> ValidateTextBox()
{
await Task.Delay(2000);
if (!int.TryParse(textBox1.Text, out _)) {
return "Not Valid";
}
//otherwise
return null;
}
private async Task<int> ReadTextBox()
{
await Task.Delay(3000);
if (!int.TryParse(textBox1.Text, out var result))
{
throw new Exception("Don't do that");
}
return result;
}
private async Task IncrementTextBox()
{
await Task.Delay(3000);
if (!int.TryParse(textBox1.Text, out var result))
{
throw new Exception("Don't do that");
}
textBox1.Text = (result + 1).ToString();
}
If you type something that's not an int into the text box and press the button, a few seconds go by, and then Not Valid shows up in the label.
If there is a number there, then there is a pause and the number shows up in the label. Then another pause and the text box number will increment by 1. Finally after another pause, the label will show the incremented value.
Note that this all runs on a single thread. But, in spite of all the delays, the UI remains responsive the whole time.
Put breakpoints at the start of each function and on the lines after each of the awaits in the button click handler. Step through (not into) the whole thing and you'll see how the awaits create continuations
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.
I'd like to understand the TPL a little bit better. How would I for example write something to the screen until a task finishes. I can't call 'await' because I want the main thread to be notified instead of proactively calling 'await' and I don't want to stop execution until the task is finished.
Some example code:
var task = Task.Run(()=>
{
Task.Delay(10000);
});
while(true)
{
Console.WriteLine("Running...");
//I want to exit the loop the second 'task' finishes
//and print 'finished'
}
There are a a couple of ways you cam achieve this:
First you can use Lambda expression in Order to invoke your action, but look at the code:
using System;
using System.Threading;
using System.Threading.Tasks;
public class Example
{
public static void Main()
{
Console.WriteLine("Application thread ID: {0}",
Thread.CurrentThread.ManagedThreadId);
var t = Task.Run(() => { Console.WriteLine("Task thread ID: {0}",
Thread.CurrentThread.ManagedThreadId);
} );
t.Wait();
}
}
// The example displays the following output:
// Application thread ID: 1
//
notice the t.Wait():
The call to the Wait method ensures that the task completes and
displays its output before the application ends. Otherwise, it is
possible that the Main method will complete before the task finishes.
So we understand that it's imperative to call the Wait() method in order make sure that the task completes and displays its output.
You can use the second way also:
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
public class Example
{
public static void Main()
{
var list = new ConcurrentBag<string>();
string[] dirNames = { ".", ".." };
List<Task> tasks = new List<Task>();
foreach (var dirName in dirNames) {
Task t = Task.Run( () => { foreach(var path in Directory.GetFiles(dirName))
list.Add(path); } );
tasks.Add(t);
}
Task.WaitAll(tasks.ToArray());
foreach (Task t in tasks)
Console.WriteLine("Task {0} Status: {1}", t.Id, t.Status);
Console.WriteLine("Number of files read: {0}", list.Count);
}
}
For more reference see Task.Run Method.
One highlight regarding your quesion:
taken from Asynchronous programming with async and await (C#):
An async method typically contains one or more occurrences of an await
operator, but the absence of await expressions doesn’t cause a
compiler error. If an async method doesn’t use an await operator to
mark a suspension point, the method executes as a synchronous method
does, despite the async modifier. The compiler issues a warning for
such methods.
That implies that either way you will have to wait for your tasks to finish and the main thread will have to wait this way or another.
The ContinueWith function is a method available on the task that allows executing code after the task has finished execution. In simple words it allows continuation.
Things to note here is that ContinueWith also returns one Task. That means you can attach ContinueWith one task returned by this method.
Task<string> t = Task.Run(() => LongRunningOperation("Continuewith", 500));
t.ContinueWith((t1) =>
{
Console.WriteLine("Running...");
});
You can achieve your goal using creating separate function to use in Task.Run and passing parameter by reference. Function should be something like below.
private void PerformTask(ref bool isComplete)
{
System.Threading.Thread.Sleep(5000);
isComplete = true;
}
Call above function from Task.Run. Your current function should be like below.
bool isComplete = false;
System.Threading.Tasks.Task.Run(() => PerformTask(ref isComplete));
while (!isComplete)
{
Console.WriteLine("Running...");
System.Threading.Thread.Sleep(1000);
}
Try to do something like this:
var task = Task.Run(() =>
{
Task.Delay(10000).Wait();
});
bool terminate = false;
while (!task.GetAwaiter().IsCompleted && !terminate)
{
// do something
if (task.GetAwaiter().IsCompleted) break;
// do something heavy
if (task.GetAwaiter().IsCompleted) break;
// do another heavy operation
for (int i = 0; i < 10000; i++)
{
// it took too long!
if (i == 1000)
{
terminate = true;
break;
}
}
}
I am new to async/await in C#. This is what I'm trying to do:
private async Task LoadSomeData()
{
/*
*This is where the 'Data' is loaded with HTTP
*/
//Data loading finished. Need to return control to next line from caller function and use this 'Data'
// Also need to use 'Data' to load 'Data2' over HTTP but is not very important
// and hence can be run in background. No piece of code depends on this currently.
}
private async void UIEventHandler()
{
//await until 'Data2' has loaded
//Continue handling the event after Data2 is loaded
}
My question is, how do I achieve the above operation. I don't want to return from LoadSomeData() method after retrieving Data2 as the current operation does not depend on it.
Below is some quick code I threw together around your method names. I've made them static just for convenience.
using System;
using System.Threading;
using System.Threading.Tasks;
public class Program
{
public static void Main()
{
Console.WriteLine("Main Start");
UIEventHandler(2000);
UIEventHandler(500);
UIEventHandler(1000);
Console.WriteLine("Main Stop");
Thread.Sleep(3000); // wait for tasks to finish
}
private static async Task LoadSomeData(int delay)
{
await Task.Run(() =>
{
Console.WriteLine("Start (LoadSomeData) " + delay);
Thread.Sleep(delay);
Console.WriteLine("Stop (LoadSomeData) " + delay);
});
}
private static async Task UIEventHandler(int delay)
{
Console.WriteLine("Start (UIEventHandler) " + delay);
await LoadSomeData(delay);
Console.WriteLine("Stop (UIEventHandler) " + delay);
}
}
This is sample output from a test run:
Main Start
Start (UIEventHandler) 2000
Start (LoadSomeData) 2000
Start (UIEventHandler) 500
Start (UIEventHandler) 1000
Main Stop
Start (LoadSomeData) 500
Start (LoadSomeData) 1000
Stop (LoadSomeData) 500
Stop (UIEventHandler) 500
Stop (LoadSomeData) 1000
Stop (UIEventHandler) 1000
Stop (LoadSomeData) 2000
Stop (UIEventHandler) 2000
You will notice that every call to UIEventHandler showed it's "Start" message straight away. However, the "Stop" message is not shown until the respective call to LoadSomeData is complete. The await operator is essentially telling the code in UIEventHandler to stop until the task in the called method is complete.
That's a really simplistic view of it, though. I'd suggest doing some reading. This might be a good start:
Asynchronous programming
private async Task LoadSomeData()
{
var data = await Task.Delay(1000); // Replace with your HTTP GET
return data;
}
private async Task LoadSomeData2(Data data)
{
var data2 = await Task.Delay(1000); // Replace with your other HTTP GET
return data2;
}
private async void UIEventHandler()
{
var data = await LoadSomeData();
var data2 = await LoadSomeData2(data);
}
UPDATE:
I recommend you read Async/Await - Best Practices in Asynchronous Programming
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.