I have a grid that loads lots of information when a row is selected - 7 more grids and a DevExpress report need to load, and it takes a lot of time
I put all the methods into tasks to speed up the process.
But if another row is selected before the previous one finishes loading, it causes errors.
I would like to know how to check if the task is finished and the either wait or cancel the task before loading again with new data. (I am new to asynchronous programming)
This is an example of my tasks (there are 8 of them, each called one after another):
private async void LoadSSNs()
{
await Task.Run(() => grdSSNs.DataSource = ICTBLL.GetData(ID));
}
How can I change it into a Task object that I can check if complete?
You should almost never have a void return type with async/await (there are exceptions, but start with that). Your method needs to return a Task so you have something to wait on or check for completion status.
private async Task LoadSSNs()
{
await Task.Run(() => grdSSNs.DataSource = ICTBLL.GetData(ID));
}
How you determine if the task is complete depends on what you need to do. If you need to do some work while the task runs asynchronously, you could do this:
var t = LoadSSNs();
// do something while task is running.
t.Wait(); // this is one option.
if (t.Status == TaskStatus.Faulted) { } // handle problems from task.
If you have more work to do while the task completes, you could do something like this:
while(!t.IsCompleted)
{
// do some other work.
}
Again, what you do with the task is up to you; the important part is you need to return an awaitable Task from your async method.
Related
So I have my progress bar in my form as 'Marquee' style so it should continuously run, however when I click my button so that the progress will appear, it is froze and does not move, however if I don't hide the progressbar at the start it will run normally.
I only want it to appear when the button is clicked though, any ideas around this?
public Form1()
{
InitializeComponent();
progressBar1.Hide();
}
private void button1_Click(object sender, EventArgs e)
{
progressBar1.Show();
DrawingHandler MyDrawingHandler = new DrawingHandler();
MyDrawingHandler.GetConnectionStatus();
try
{
Operation.RunMacro("shaftCheck.cs");
DrawingEnumerator SelectedDrawings = MyDrawingHandler.GetDrawingSelector().GetSelected();
if (SelectedDrawings.GetSize() == 0)
{
MessageBox.Show("Error, no drawings to export.");
}
else
{
Operation.RunMacro("ExportShaft2.cs");
}
}
catch (Exception)
{
MessageBox.Show("Error");
}
}
}
The most likely reason is that you are doing some kind of slow operation on the UI thread.
There is in most cases only one UI thread, this is the only thread allowed to update the UI, and this can only do one thing at a time. If you are using the UI thread to do some kind of processing it cannot do other things, like updating your UI.
The solution is to put all processing intensive operation on a background thread. For example with Task.Run. But you will need to ensure any called code does not trigger any UI updates.
If you just have a progress bar as part of the dialog it is fairly easy. But it results in the user being able to do other things while you are doing the processing, so you need to be super-careful that all your code is thread safe.
A safer option is usually to show a modal dialog that prevents the user from doing anything else. This greatly reduces the risk of thread safety issues. Typically it would look something like this:
var progressForm = new MyProgressForm();
Task.Run(MyWorkerMethod)
.ContinueWith(t => progressForm.DialogResult = DialogResult.OK, TaskScheduler.FromCurrentSynchronizationContext());
progressForm .ShowDialog();
Is there another property in the progressbar that is a better fit for your needs. Winforms Progress Bar Visible true false in this post it looks like you can change the visibility with the Visibility property.
Your program has only one thread that may update the UI. If you keep this thread busy doing other things, then your UI won't be updated, nor will it respond to operator input.
void LongRunningMethod() {...}
private void OnButton1_Clicked(object sender, ...)
{
this.progressBar1.Visible = true;
this.LongRunningMethod();
this.progressBar1.Visible = false;
}
While LongRunningMethod is being executed, the UI won't respond: the progressbar is not updated, the UI does not respond to user input.
There are two often used methods to solve this.
Old fashioned: use a BackGroundWorker, and let this BackGroundWorker do the LongRunningMethod. The BackGroundWorker sends events when it is finished. You can use that event to hide the progressBar again.
Modern: use async-await. Let a separate Task do the LongRunningMethod.
I won't discuss the BackGroundWorker. If you understand event handling, you will get the gist of it. I'll describe async-await instead.
What really helped me to understand async-await was this interview with Eric Lippert. Search somewhere in the middle for async await.
In this interview Eric Lippert compares async-await with a cook making breakfast. Whenever the cook has to wait for something, like a kettle of water to boil, he doesn't wait idly, no, he looks around to see if he can do something else instead, like insert bread in the toaster. He doesn't wait for the bread to be toasted, he starts scrambling eggs. Later he returns to the boiling water to make tea, or to the toaster to get the toasted bread.
Async-await is similar: whenever your thread has to wait for another process to finish, like writing a file, reading from a database or from the internet, you can let the thread wait idly until the other process completed the task. You could also let the thread do other things, like updating the progressbar and listening to user input. This is called async-await.
Whenever your thread sees an await, it does not wait idly, but it goes up the call stack and execute the code until the caller has an await, up the call stack again and execute the code until the thread sees an await, etc.
Later, when the file-write is finished, or the database data is fetched, or the internet data is downloaded, the thread (or to be precise: any thread from the thread pool) will execute the code after the await.
To be able to use async-await, do the following:
Whenever your program has to wait for another lengthy process, like the examples that I gave above, find the async version of the process: WriteAsync / ReadAsync etc
Define your method async. It is common usage to terminate the identifier of the method with Async: ReadFileAsync, GetProductsAsync, etc. This will make it possible to also have a non-async version: ReadFile, GetProducts.
Return Task<TResult> instead of TResult; return Task instead of void.
There is one exception to this rule: event handlers always return void: no one can await for the result of an event handler
Inside the async method call the WriteAsync / ReadAsync etc. Don't await until you need the results of the async action. await before your async method returns
If the return is Task<TResult>, the result of the await is TResult. If you await Task, the return is void.
So if you need to read lines of text from a file:
private async Task<List<string>> ReadFileAsync(string fileName)
{
using (TextReader textReader = new StreamReader(fileName))
{
List<string> lines = new List<string>();
string line = await textReader.ReadLineAsync();
while (line != null)
{
// a line has been read, add it to the lines, and read the next
lines.Add(line);
line = await textReader.ReadLineAsync();
}
}
}
So if the operator presses a button to read the file and to process the read lines async:
private async Task ProcessLinesAsync(IEnumerable<string> linesToProcess) {...}
private async Task ReadAndProcessFileAsync()
{
string fileName = this.GetFileName();
List<string> lines = await this.ReadFileAsync(fileName);
await this.ProcessLinesAsync(lines);
}
private async void OnButton1_Clicked(object sender, ...)
{
this.ShowProgressBar();
await this.ReadAndProcessFileAsync();
this.HideProgressBar();
}
Note that the event handler returns void instead of Task.
ShowProgressBar is a method that will initialize the progressBar before showing it using this.progressBar1.Visible = true;.
Use other thread to do lengthy calculations
Until now, the UI thread had to wait for another process to finish. Async-await can also be used if you need to do some length calculations while keeping the UI responsive. Use Task.Run to let one of the available threads in the thread pool do the lengthy calculations. Wait for it when you need the results:
private MyResult DoLengthyCalculations()
{
// Do your lengthy calculations here:
DrawingHandler MyDrawingHandler = new DrawingHandler();
MyDrawingHandler.GetConnectionStatus();
try
{
Operation.RunMacro("shaftCheck.cs");
// etc
}
private async Task<MyResult> DoLengthyCalculationsAsync()
{
MyResult result = await Task.Run( () => DoLengthyCalculations();
return result;
}
By the way: this is an example where you have an async and a non-async method: the caller can decide which one he wants to use.
The event handler:
private async void OnButton1_Clicked(object sender, ...)
{
this.ShowProgressBar();
await this.DoLengthyCalculationsAsync();
this.HideProgressBar();
}
Continue processing after the other task started
If you can do something useful instead of awaiting for the task to finish, don't await yet. Await as late as possible: only when you need the result, and before returning.
async Task DoMyWorkAsync()
{
// start reading the file. Don't await, while the file is being read,
// you can do other things:
Task<List<string>> taskReadFile = this.ReadFileAsync();
// because you didn't await, you are free to do something else as soon as
// the thread sees an await:
this.DoSomethingElse();
// you can even start a second task:
Task<MyResult> taskLengthyCalculations = this.DoLengthyCalculationsAsync();
// as soon as you need the results, await for it:
List<string>> readLines = await taskReadFile;
this.ProcessReadLines(readLines);
...
If you want: wait for both tasks to finish:
Task[] allTasks = new Task[] {taskReadFile, taskLengthyCalculations};
await Task.WhenAll(allTasks);
// you can access the return value using property Result:
List<string>> readLines = taskReadFile.Result;
MyResult lengthyCalculationsResult = taskLengthyCalculations.Result;
this.Process(readLines, lengthyCalculationsResult);
For an async method that returns a Task<bool>, I need to take some actions when the method completes. The async method looks like this:
async Task<bool> EntryExists(string entry)
{
return await Task.Run(() => call_that_returns_bool());
}
I call it and attach a continuation task to it to perform follow-up actions:
EntryExists(my_entry).ContinueWith(t =>
{
if(t.Result) ...
});
However, I now need to conditionally wait for chained task to complete. Means depending upon a parameter, I either need to return immediately to the caller, or wait till the tasks finish. I change the above code to look like this:
var T = EntryExists(my_entry).ContinueWith(t =>
{
if(t.Result) ...
});
if(wait) T.Wait(); //wait is my parameter
Running this, the code gets stuck forever at T.Wait() when wait parameter is true, as if T never kicked off. I then tried the following:
var T = EntryExists(my_entry).ContinueWith(t =>
{
if(t.Result) ...
});
T.Start();
if(wait) T.Wait();
Upon which it tells me that
Start may not be called on a continuation task
I know I'm missing something basic, but after been coding for the last 15 hours, my brain isn't helping much. Can someone point out what I need to do?
You shouldn't block on async code. In short, you're very likely to be blocking the thread that the async method needs to return to (in this case you are, as it's the UI thread). The solution is to use async-await all the way through, rather than trying to run it synchronously. If you absolutely have to present a synchronous method, then at least provide as simpler wrapper as possible, rather than mixing ContinueWith and async-await.
Your outer call can be rewritten as:
async Task<{something}> MakeCallAndContinue()
{
try
{
await EntryExists(my_entry);
// additional continuation code
}
catch (Exception e)
{
// handle in some way
}
}
var task = MakeCallAndContinue();
if (wait) await task;
It's unusual to want to start a task and then not await it, which is what you're doing if wait is false. The error handler I've put in the above code is to ensure that you don't get an exception thrown on to an unawaited task. If you did that, then it would be thrown out somewhere else, and probably kill your process if you haven't declared a global handler.
You won't be able to use the above in your WPF command as-is, because it's async. However, you can have async WPF command handlers, as explained here. If you did want to do it synchronously then you would need to call .Wait(), but as Stephen Cleary explains in my first link, you have to use ConfigureAwait(false) on all awaited tasks all the way down in order to prevent one of them from trying to return to the occupied UI thread, and deadlocking.
Apologies for the bad title, I'm not sure how to succinctly describe this.
I'm building a service in .net core to process files. The general idea would be to (in a loop) check for new tasks to run on a file by using a DB call, and if found, fire them off async. There would be a throttler to limit the number of running tasks. If it hit the limit, it would just wait until a task is finished before firing off a new one. If the DB call returns nothing, then it would just sleep for a bit and try again later.
Fairly basic I think, but I'm running into issues because everything I've read says you should always await a task and not "fire and forget". But if I do that, then I'm left either running files synchronously or batching them. I'm missing something I'm sure.
Currently it's implemented as a IHostedService (BackgroundService specifically). Here us the main ExecuteAsync method that does the work. Implemented as fire and forget. (Visual studio gives the "call not awaited" warning on Task.Run)
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
var throttleTimeout = 10000;
//set up semaphore
var taskThrottler = new SemaphoreSlim(10, 10);
while (!stoppingToken.IsCancellationRequested)
{
//wait for free slot
await taskThrottler.WaitAsync(throttleTimeout,stoppingToken);
//get next file to process
var currentFile = await _fileService.GetNextFileForProcessing();
// create task
Task.Run( async
() =>
{
try
{
//do work with file tracker
var result = await _fileProcessorController.ProcessFile(currentFile);
}
finally
{
taskThrottler.Release();
}
}
, stoppingToken);
}
}
Now if I change that and tack on an await before Task.Run, then I'm (essentially) running synchronously because each task will be awaited before the next is fired..
If I add the tasks to a list I can use "await Task.WhenAll(tasks);". But then I'm batching.
I need to be able to gracefully handle failed processing jobs, so an await in some form is a must I think.
All the examples I've found that tackle a similar problem usually have the list of tasks (or files) to do in advance, and then just iterate through. But I'm not sure what the best method is when I need to add tasks to the list while processing others.
Perhaps something that uses a task list and WhenAny? And then can I add new tasks to the task list on each loop if any are found?
I may get voted as a duplicate of
wrapping-synchronous-code-into-asynchronous-call
However, My question is what if I don't care about the results of the task?
More detail: I want the task to run and whether or not it finishes, I want the task to run again in another thread.
To explain specifically, I have a service that reads a table and gets all the records that have not been processed. The task does it's business, but I don't know if there is one record or 1000 records to be processed in that instance. If it is 1000, it will take several minutes, one will take less than a second, usually the task finds nothing to do. So in that case I don't need to know the results of the previous task nor wait for it to finish.
I have read on async and if I do not consume the await result, I read that it will not continue. Is that true?
The example is:
private async Task MakeRequest()
{
mainTimer.Stop();
var task = Task.Run(() => Exec());
await task;
mainTimer.Start();
}
does this mean that the task is not ready to run again unless I have the "await task" command?
await task;
States that you want to wait for task completion and continue execute next lines.
When you run this:
Task.Run(() => Exec());
It start to execute new task immediately, doesn't matter did you use await next or not. You can run the same function in a task as many times as you want without using keyword await. But you need make sure that your function can handle concurrent execution.
If you need to get result of your task without using await, you can continue execution on the same thread on which task was started:
task.ContinueWith(task=> {});
if you don't care about the result, then use a void function:
private async void MakeRequest()
{
mainTimer.Stop();
var task = Task.Run(() => Exec());
await task;
mainTimer.Start();
}
Also, not consuming a task does not block anything, it will finish even if you don't await it.
Trying to advance from using BackgroundWorker to Task, I am getting confused on how to keep the background job running without calling Wait().
This is the background job (simplified):
private async Task RunAsync()
{
HttpResponseMessage response = await TheHttpClient.GetAsync(Path);
if (response.IsSuccessStatusCode)
{
textBox_Response.Text = await response.Content.ReadAsStringAsync();
}
}
When the Send button is clicked, the above code should run, but because the background code has more than one await async calls, I guess that there are several Wait() calls needed:
private void button_Send_Click(object sender, EventArgs e)
{
Task t = RunAsync();
while (!t.IsCompleted)
{
t.Wait();
}
}
But this would block the GUI during the entire processing time of the background job.
How can I start the background job and return immediately from the button click handler, while allowing the background job to run all async calls?
I know how to achieve this with the BackgroundWorker, should I not use a Task here?
Event handlers are the only place you are allowed to do async void, what you do is make the event handler async and await it there
private async void button_Send_Click(object sender, EventArgs e)
{
await RunAsync();
//Do code here that needs to run after RunAsync has finished.
}
Quite often people think that async await is an asynchronous process performed by several threads, but in fact it is all done by one thread, unless you start a new thread using Task.Run or similar functions.
In this interview (somewhere in the middle. Search for async) Eric Lippert compared the async-await by the works of a cook in a restaurant. If he is toasting bread, he could wait for the bread to be ready before boiling the eggs, OR he could start boiling eggs and get back to the bread afterwards. It looks like the cook is doing two things at the time, but in fact he is only doing one thing, and whenever he has to wait for something he starts looking around to see if he can do other things.
If your one-and-only thread calls an asynchronous function, without awaiting for it. Your one-and-only thread starts executing that function until he sees an await. If he sees one, he doesn't wait until the async function completes, instead he remembers where he was awaiting and goes up in his call stack to see if his caller has something else to do (== is not awaiting). The caller can do the next statements until he meets an await. In that case control is given back up the call stack to the caller until he awaits etc. If your one-and-only thread is awaiting in all functions in the call stack control is given back to the first await. When that is finished your thread starts doing the statements after the await until he meets another await, or until the function is finished.
You can be certain that every async function has an await somewhere. If there is no await it is not meaningful to create it as an async function. In fact your compiler will warn you if you forgot to await somewhere in your async function.
In your example, you can expect an error, or at least a warning that you forgot to declare your button_send_click async. Without this the procedure can't await.
But after you've declared it async, and the button is pressed, your GUI-thread will call RunAsync where it will enter function TheHttpClient.GetAsync.
Inside this function is an await ReadAsStringAsync, and because ReadAsStringAsync is declared async, we can be certain that that function has an await in it. As soon as this await is met, control is given back to your TheHttpClient.GetAsync. This function would be free to perform the next statement if it didn't await. An example would be like this:
private async Task RunAsync()
{
var responseTask = TheHttpClient.GetAsync(Path);
// because no await, your thread will do the following as soon as GetAsync encounters await:
DoSomethingUseFul();
// once your procedure has nothing useful to do anymore
// or it needs the result of the responseTask it can await:
var response = await responseTask;
if (response.IsSuccessStatusCode)
...
The await is after DoSomethingUseful(). Therefore, the function can't continue. Instead of doing nothing until responseTask is finished, control is given back to the caller: button_send_click. If that function wasn't await it would be free to do other things. But since the button_send_click is awaiting control is given back to the caller: your UI is free to do other things.
But remember: it is always the one-and-only cook who makes your breakfast Your thread can do only one thing at a time
The advantage is that you won't run into difficulties you have with multiple threads. The disadvantage is that as long as your thread doesn't meet an await, it is too busy to do other things.
If you need to do some lengthy calculation while you don't want to be busy doing the calculation you can start a separate thread doing this calculation. This gives your thread time to do other things, like keeping the UI responsive until it needs the results of the calculations:
private async void Button1_Clicked(object sender, ...)
{
var taskLengthyCalculation = Task.Run( () => DoLengthyCalculation(...));
// while a different thread is doing calculations
// I am free to do other things:
var taskRunAsync = RunAsync();
// still no await, when my thread has to await in RunAsync,
// the next statement:
DoSomethingUseful();
var result = await taskRunAsync();
var resultLengthyCalculation = await taskLengthyCalculation;