C# Windows application show picture box until background process finish - c#

I have to call my API and show waiting PictureBox(wait.gif) until API get complete and return the data to bind my custom control into tablepanellayout.
I can't use BackgroundWorker class here because it has cross-thread issue with my sub control in custom control.
Here I have only idea to do that, is call child thread from main thread but until its get executed completely show the PictureBox(wait.gif) and block the rest code to be executed.
Can anybody suggest me how to do it exactly or please provide some code snippet for example.

There are two articles that helped me a lot understanding async-await:
This interview with Eric Lippert. Search somewhere in the middle for async aawait. Eric compares async await with a cook who doesn't wait for the water to boil, but instead looks around if he can do something else in the mean time.
Async Await by the ever so helpful Stephen Cleary
For WinForms you do the following:
If your data query function has async versions to fetch the data, use that function. Think of functions like SqlConnection.OpenAsync, Dapper.QueryAsync etc
If your data querier has no async versions make it async using Task.Run
Every function that calls async functions should be declared async itself
Every async function returns Task instead of void and Task<TResult> instead of TResult.
The only exception is the event handler: this function returns void instead of Task
the calls to other async functions should be awaited before your async returns.
.
// The event handler: make async. The only one that still returns void
async void OnButton1_clicked(object sender, ...)
{
// start fetching the data. Don't await yet, you'll have other things to do
Task<MyData> fetchDataTask = FetchData(...);
// meanwhile: show the user that you are busy:
this.ShowBusy(true); // show picture box?
// if needed do other things you can do before the data is fetched
this.ClearTable();
// once you have nothing meaningful to do, await for your data
MyData fetchedData = await fetchDataTask;
this.ProcessData(fetchedData);
// finished:
this.ShowBusy(false); // remove picture box
}
Async version of the function that fetched the data:
async Task<IQueryable<MyData>> FetchDataAsync(myParams)
{
using (SqlConnection dbConnection = new SqlConnection(...)
{
// open the connection, don't wait yet:
Task taskOpen = sqlCommand.OpenAsync();
// continue while opening:
using (var sqlCommand = new SqlCommand(...))
{
cmd.Parameters.AddWithValue(...);
// before executing the query: wait until OpenAsync finished:
await taskOpen;
// read the data. If nothing to do: await, otherwise use Task similar to Open
SqlDataReader dataReader = await cmd.ExecuteReaderAsync();
foreach (var row in dataReader)
{
... (some Await with GetFieldValueAsync
}
}
}
}
I'm not really familiar with reading SQL data on such a low level, I prefer entity framework and dapper, so there might be an error in my SqlReader stuff. Maybe someone can correct this. Still you'll get the gist.
If you write it like this, your program will be pretty responsive: Whenever the procedure has to await for something, control is given back to the caller of the function who can continue processing until he meets an await, when control is given back to the caller, who continues processing, etc.
Note that this won't help you if your program is not waiting for something. If your main thread does some heavy calculations for several seconds, your program won't be responsive. Consider creating an async function that will do this for your using Task.Run
If you have programmed like this, all threads performing your functions will have the same context: it will be as if only the UI-thread is involved. No need for mutexes, semaphores, InvokeRequired etc.

Related

C# winforms, progress bar will freeze on button click event

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);

how to await until parallel task done

I'm new with C#. I'm writing window form for sorting files inside folder according to it extension.
It's work when do the task with one folder but I modified it to do it from multiple item in listbox.
private async void startBtn_Click(object sender, EventArgs e)
{
if (this.listBox1.Items.Count != 0)
{
this.statusLabel.ForeColor = Color.DodgerBlue;
this.statusLabel.Text = "Sorting";
this.startBtn.Enabled = false;
this.removeOtherCheck.Enabled = false;
this.workerCounter.Enabled = false;
foreach (var item in this.listBox1.Items)
{
if (Directory.Exists( (string)item ))
{
await Task.Run(() => startTask((string)item, this.removeOtherCheck.Checked, this.workerCounter.TabIndex));
}
}
FinishedTask();
}
private async void startTask(string path, bool removeOtherFlag, int worker)
{
await Task.Run(() => doJob(path, removeOtherFlag, worker));
}
private void FinishedTask()
{
this.statusLabel.ForeColor = Color.LimeGreen;
this.statusLabel.Text = "Finished";
this.startBtn.Enabled = true;
this.removeOtherCheck.Enabled = true;
this.workerCounter.Enabled = true;
}
//this method are seperate but I put it here so you guy can see it
public static void doJob(string directory,bool removeOtherFlag, int worker)
{
// loop in directory
createFolders(directory); // create extension folder
string[] all_files = Directory.GetFiles(directory);
Parallel.ForEach(all_files, new ParallelOptions { MaxDegreeOfParallelism = worker }, (item) => multiprocessingFiles(item));
}
if(removeOtherFlag == true) deleteOtherFolder(Path.Combine(directory,"other"));
removeEmptyFolder(directory); // remove empty extension folder
}
I'm gonna explain my task.
first I click start button when process start it will disable all buttons, then loop for each items in listbox and sorting all files in folder.
when everything finished it will show finished label and enable all buttons.
the thing is, it show finished label and re-enable all buttons before removeEmptyFolder() doing it job.
I try change Parallel.forEach to Parallel.For but it's not doing my thing.
EDIT
Thank you for all answer.
Thank Harald Coppoolse for your conclusion.
Paulo Morgado is right.
I remove startTask and change
await Task.Run(() => startTask((string)item, this.removeOtherCheck.Checked, this.workerCounter.TabIndex));
to
await Task.Run(() => doJob(item, this.removeOtherCheck.Checked, this.workerCounter.TabIndex));
Now everything is working perfectly as I want.
Thank you everyone.
Are you looking for someting like Task.WaitAll(params Task[] tasks)?
Then you could cange doJob to async by,
replaceing Parallel.ForEach with:
var tasks = all_files.Select(f => Task.Run(multiprocessingFiles(f)));
await Task.WaitAll(tasks);
Or if you want to limit the max parallel tasks:
Create non running tasks via Task t = new Task(() => doSometing());
and start them in batches with t.Start(); and await Task.WaitAll(batch);
However as pointed out in the comments I do not think this will improve performace.
In winforms, when you use async-await, you only use Task.Run when you need to start an extra thread that will do a job that takes some considerable amount of time, longer than you want your program to freeze. You don't call Task.Run for async methods, because properly designed async methods won't freeze your UI.
As soon as a thread that executes an async method sees await, it doesn't wait idly for the procedure until it is finished, instead if goes up its call stack to execute code until is sees an await. Goes up the call stack again, and executes code until is sees an await, etc.
Result: if an async event handler only uses async methods, your UI won't freeze. Unless one of the async methods does some heavy calculations (= use long non-async functionality)
If you want to keep your UI responsive during those heavy calculations, you should create an async method that calls the procedure with the heavy calculations using Task.Run.
But I did all that!
Yes you did, but you also had an async function that called another async fucntion using Task.Run! And that was not necessarry.
BTW, it might be a good idea to stick to coding conventions, like using camel casing and adding Async in async methods. This will help future readers to understand your code.
void DoJob(...){...} // your time consuming method with heavy calculations
The async version of DoJob. Apparently there is nothing we can do async in DoJob, so this version has to call the DoJob:
async Task DoJobAsync(...)
{
// call the non-async version on a separate thread:
await Task.Run( () => DoJob(...)).ConfigureAwait(false);
}
I named the procedure DoJobAsync, because the pre- and postconditions are the same as in DoJob. This matches all other non-async / async pairs: Stream.Write and Stream.WriteAsync, File.Read and File.ReadAsync, Queryable.ToList and Queryable.ToListAsync.
If in future versions DoJobAsync can use some async methods, for instance because someone invents a procedure MultiprocessingFilesAsync, then only DoJobAsync has to change, no one else will know.
For ConfigureAwait(false) see Stephen Cleary's [Best Practices in Asynchronous Programming][1]
BTW: are you sure that it is wise to do the disk handling in a Parallel.Foreach? Did you measure that it is more efficient than a standard foreach?
Anyway, apparently you have some user interface element that will start the process of "doing the job" While this job is being processed, you want to give some visual information to the operator that the job is busy, and you want to tell the operator that the job is finished. You already invented FinishedTask, why not create a StartTask (and use better descriptive names: verbs for methods)
void ShowTaskStarted() {...}
void ShowTaskCompleted() {...} // was: FinishedTask
Apparently the items in listBox1 are strings.
async Task ProcessItems(IEnumerable<string> itemsToProcess,
bool removeOtherFlag, int worker) // TODO: invent proper name
{
foreach (string itemToProcess in itemsToProcess)
{
await DoJobAsync(itemToProcess, removeOtherFlag, worker);
}
}
If you think that you can start a second DoJobAsync before the first has completely finished, then start the next job before the previous one is completed:
List<Task> jobs = new List<Task>();
foreach (string itemToProcess in itemsToProcess)
{
Task jobTask = DoJobAsync(itemToProcess, removeOtherFlag, worker);
jobs.Add(jobTask);
}
await Task.WhenAll(jobs);
Because you job is some disk handling, I'm not sure it is wise to do this, but keep this in mind, if for instance you are starting tasks which can be startedwhile the previous one is not finished.
Until now, the procedures didn't know that the data came from a listbox, nor from a CheckBox or a TabControl. I did this, because if later you decide to change the source of the data, for instance a ComboBox, or a DataGridView, these procedures don't have to change. Below is the first procedure that knows about your form.
This is a strict separation of your Model (= data and how the data is processed) and the View (= how the data is displayed).
Other advantages of separating your Model from your View:
you can put the Model outside you Form (the Form HAS the Model = aggregation, or composition). This way, this Model can be used by several Forms.
a separated Model can be unit tested without the Form
If you give the Model an interface, you can change the Model, without having to change the Form.
With the interface, you can mock the model during development of your interface.
So consider to always separate your Model from your View.
The View
I don't know what is in your listbox, so I can't give the next procedure a proper name.
async Task ProcessListBox() // TODO: proper name
{
ShowTaskStarted();
var itemsToProcess = this.ListBox1.Items.ToList();
var removeOtherCheck = this.removeOtherCheck.Checked;
var worker = this.workerCounter.TabIndex;
await ProcessItems(itemsToProcess, removeOtherCheck, worker);
ShowTaskCompleted();
}
And finally: you want to process the ListBox when the operator clicks the start button:
async void StartButton_Clicked(object sender, ...)
{
await ProcessLisbBox().ConfigureAwait(false);
}
Because I separated the action (what must be done) from the trigger (when must it be done), the following will be a one liner method:
async void MenuItem_EditStart_Clicked(object sender, ...)
{
await ProcessLisbBox().ConfigureAwait(false);
}
Or maybe you want to do it during loading the form: add one line is enough
Conclusions
When using async-await: go async all the way.
async methods always call async versions of other methods
If a time consuming method doesn't have an async alternative, create one, and let it Task.Run the non-async version. Outside this procedure no one knows that a separate thread is started.
conventions: async methods are suffixed Async
Don't make one procedure that does everything. Smaller procedures are easier to understand, easier to reuse, easier to change and to unit test
Separate the model from the view, preferably using an interface
CamelCase your Methods, use Verbs.
[1]: https://learn.microsoft.com/en-us/archive/msdn-magazine/2013/march/async-await-best-practices-in-asynchronous-programming

Does the following code sequence make sense in C#

I haven't used async/await very often and I'm not fully comfortable with them. I am trying to make an operation that is synchronous to be run asynchronously. Can you tell me if the following code snippet makes sense:
public static async Task<string> FileVersionAsync(string localFilePath)
{
FileVersionInfo versionInfo;
try
{
versionInfo = await Task.FromResult(FileVersionInfo.GetVersionInfo(localFilePath));
}
catch (SecurityException)
{
return "File Version Checker does not have permission to read file version";
}
catch (FileNotFoundException)
{
return "Unable to find configured file";
}
if (versionInfo.FileVersion == null)
return "N/A";
return versionInfo.FileVersion;
}
Adding Task, await and async do not make something asynchronous; they merely provide the plumbing to work with asynchronous code when it happens. In your example: it never happens asynchronously, so all you are doing is adding plumbing overhead for no benefit.
The compiler will generate a ton of extra code that will turn out to never be hit, because when it gets to the await it'll discover that the task is already complete, and will simply continue on the existing thread.
To actually be asynchronous, you need ... something that is async. This could be external IO, or could be something threading related - but note that simply jumping to another thread doesn't buy you anything: it just adds a context switch.
If there was a FileVersionInfo.GetVersionInfoAsync method, what you are doing might be worthwhile.
No it does not make sense.
The only reason to make your function async is if somewhere inside it awaits other functions that are async. In fact your compiler warns you if you forget to await somewhere.
The async-await syntax was invented as a replacement for other task functions like Task.ContinueWith, Task.FromResult, Task.FromException etc.
In this interview Eric Lippert compared async-await with a cook who has to prepare breakfast Search somewhere in the middle for async-await.
If a cook has to prepare breakfase he starts to boil water. But instead of waiting for the water to cook, he starts slicing bread, and do other things. Only after he has nothing to do anymore he starts waiting idly for the water to boil after which he makes the tea.
Similarly: if a program has to wait for an external process to perform a request, like a database query, write data to a file, get information from the internet etc. async-await makes sure that your thread doesn't wait idly. Instead your thread goes up its call stack to see if one of the callers can continue working without the result from the other process.
You'll see this in the following code:
public async Task<string> ReadTextFile()
{
StreamReader txtReader = File.OpenText(...);
// read the complete text file; don't wait until finished yet
Task<String> taskTxt = txtReader.ReadToEndAsync();
// as we didn't use await, we can continue processing:
DoSomething();
// now we need the result from the read action: await for it
// the result of await Task<TResult> is the TResult:
string importedTxt = await taskTxt;
return importedTxt;
}
Some guidelines for async-await:
Only use async-await if you call at least one other async function
instead of void return Task, instead of TResult return Task<TResult>
Only exception: the async event handler: this async function returns void
The return of await Task is void; the return of await Task<TResult> is TResult
If you don't need the result of an async function right now, and if you can do something meaningful while the task is processing: start the task by calling the async function, but don't await for it. Only await when you need the result
.
public async void Button_Clicked(object sender, EventArgs e)
{
// indicate you will do something time consuming:
this.ProgressBar1.Visible = true;
await DoSomethingTimeconsumingAsync(...);
// finished:
this.progressBar1.Visible = false;
}
This will make sure that whenever your thread has to wait something, it can do other things, and thus your GUI remains responsive.
No. There appears to be absolutely no need to make this method async, because Task.FromResult is ready immediately.

Changing previous synchronous method to asynchronous

I have a method called from within a program that authorizes card payment which was previously implemented in a synchronous way. However now I want to change it so it runs on a different thread so I can send cancel request once it has started.
It works, but I want to know if this is a good implementation, if there are some things I need to consider like deadlocks etc.
So here is a simplified version of my code:
public void Authorize()
{
lock(object)
{
AuthorizeAsync();
}
}
public async void AuthorizeAsync()
{
// ...
IProgress<string> progressHandler = new Progress<string>(progressString =>
{
UpdateProgressWindow(progressString.ToString());
});
cancellationToken = progressWindow.CancellationTokenSource.Token;
progressWindow.show();
results = await DoAuthorizeAsync(progressHandler, cancellationToken).ConfigureAwait(false);
// ...
}
I mainly want to use async - await because I want the authorization work to run separately from the UI thread so the user can still cancel the operation.
Do you suggest another approach other than async - await?
I am mainly concerned with the fact that I am calling an async method from sync method, I know the best practice is to use async all the way up but I cannot change the rest of the program.
The other concern I have is the lock in Authorize() could it pose any problem? I only want the code to be accessed by one thread at a time.
I am fairly new to this async - await architecture in .net so I'm pretty sure I didn't get it right on my first attempt.

Why is this code running synchronously?

I am trying to understand concurrency by doing it in code. I have a code snippet which I thought was running asynchronously. But when I put the debug writeline statements in, I found that it is running synchronously. Can someone explain what I need to do differently to push ComputeBB() onto another thread using Task.Something?
Clarification I want this code to run ComputeBB in some other thread so that the main thread will keep on running without blocking.
Here is the code:
{
// part of the calling method
Debug.WriteLine("About to call ComputeBB");
returnDTM.myBoundingBox = await Task.Run(() => returnDTM.ComputeBB());
Debug.WriteLine("Just called await ComputBB.");
return returnDTM;
}
private ptsBoundingBox2d ComputeBB()
{
Debug.WriteLine("Starting ComputeBB.");
Stopwatch sw = new Stopwatch(); sw.Start();
var point1 = this.allPoints.FirstOrDefault().Value;
var returnBB = new ptsBoundingBox2d(
point1.x, point1.y, point1.z, point1.x, point1.y, point1.z);
Parallel.ForEach(this.allPoints,
p => returnBB.expandByPoint(p.Value.x, p.Value.y, p.Value.z)
);
sw.Stop();
Debug.WriteLine(String.Format("Compute BB took {0}", sw.Elapsed));
return returnBB;
}
Here is the output in the immediate window:
About to call ComputeBB
Starting ComputeBB.
Compute BB took 00:00:00.1790574
Just called await ComputBB.
Clarification If it were really running asynchronously it would be in this order:
About to call ComputeBB
Just called await ComputBB.
Starting ComputeBB.
Compute BB took 00:00:00.1790574
But it is not.
Elaboration
The calling code has signature like so: private static async Task loadAsBinaryAsync(string fileName) At the next level up, though, I attempt to stop using async. So here is the call stack from top to bottom:
static void Main(string[] args)
{
aTinFile = ptsDTM.CreateFromExistingFile("TestSave.ptsTin");
// more stuff
}
public static ptsDTM CreateFromExistingFile(string fileName)
{
ptsDTM returnTin = new ptsDTM();
Task<ptsDTM> tsk = Task.Run(() => loadAsBinaryAsync(fileName));
returnTin = tsk.Result; // I suspect the problem is here.
return retunTin;
}
private static async Task<ptsDTM> loadAsBinaryAsync(string fileName)
{
// do a lot of processing
Debug.WriteLine("About to call ComputeBB");
returnDTM.myBoundingBox = await Task.Run(() => returnDTM.ComputeBB());
Debug.WriteLine("Just called await ComputBB.");
return returnDTM;
}
I have a code snippet which I thought was running asynchronously. But when I put the debug writeline statements in, I found that it is running synchronously.
await is used to asynchronously wait an operations completion. While doing so, it yields control back to the calling method until it's completion.
what I need to do differently to push ComputeBB() onto another thread
It is already ran on a thread pool thread. If you don't want to asynchronously wait on it in a "fire and forget" fashion, don't await the expression. Note this will have an effect on exception handling. Any exception which occurs inside the provided delegate would be captured inside the given Task, if you don't await, there is a chance they will go about unhandled.
Edit:
Lets look at this piece of code:
public static ptsDTM CreateFromExistingFile(string fileName)
{
ptsDTM returnTin = new ptsDTM();
Task<ptsDTM> tsk = Task.Run(() => loadAsBinaryAsync(fileName));
returnTin = tsk.Result; // I suspect the problem is here.
return retunTin;
}
What you're currently doing is synchronously blocking when you use tsk.Result. Also, for some reason you're calling Task.Run twice, once in each method. That is unnecessary. If you want to return your ptsDTM instance from CreateFromExistingFile, you will have to await it, there is no getting around that. "Fire and Forget" execution doesn't care about the result, at all. It simply wants to start whichever operation it needs, if it fails or succeeds is usually a non-concern. That is clearly not the case here.
You'll need to do something like this:
private PtsDtm LoadAsBinary(string fileName)
{
Debug.WriteLine("About to call ComputeBB");
returnDTM.myBoundingBox = returnDTM.ComputeBB();
Debug.WriteLine("Just called ComputeBB.");
return returnDTM;
}
And then somewhere up higher up the call stack, you don't actually need CreateFromExistingFiles, simply call:
Task.Run(() => LoadAsBinary(fileName));
When needed.
Also, please, read the C# naming conventions, which you're currently not following.
await's whole purpose is in adding the synchronicity back in asynchronous code. This allows you to easily partition the parts that are happenning synchronously and asynchronously. Your example is absurd in that it never takes any advantage whatsoever of this - if you just called the method directly instead of wrapping it in Task.Run and awaiting that, you would have had the exact same result (with less overhead).
Consider this, though:
await
Task.WhenAll
(
loadAsBinaryAsync(fileName1),
loadAsBinaryAsync(fileName2),
loadAsBinaryAsync(fileName3)
);
Again, you have the synchronicity back (await functions as the synchronization barrier), but you've actually performed three independent operations asynchronously with respect to each other.
Now, there's no reason to do something like this in your code, since you're using Parallel.ForEach at the bottom level - you're already using the CPU to the max (with unnecessary overhead, but let's ignore that for now).
So the basic usage of await is actually to handle asynchronous I/O rather than CPU work - apart from simplifying code that relies on some parts of CPU work being synchronised and some not (e.g. you have four threads of execution that simultaneously process different parts of the problem, but at some point have to be reunited to make sense of the individual parts - look at the Barrier class, for example). This includes stuff like "making sure the UI doesn't block while some CPU intensive operation happens in the background" - this makes the CPU work asynchronous with respect to the UI. But at some point, you still want to reintroduce the synchronicity, to make sure you can display the results of the work on the UI.
Consider this winforms code snippet:
async void btnDoStuff_Click(object sender, EventArgs e)
{
lblProgress.Text = "Calculating...";
var result = await DoTheUltraHardStuff();
lblProgress.Text = "Done! The result is " + result;
}
(note that the method is async void, not async Task nor async Task<T>)
What happens is that (on the GUI thread) the label is first assigned the text Calculating..., then the asynchronous DoTheUltraHardStuff method is scheduled, and then, the method returns. Immediately. This allows the GUI thread to do whatever it needs to do. However - as soon as the asynchronous task is complete and the GUI is free to handle the callback, the execution of btnDoStuff_Click will continue with the result already given (or an exception thrown, of course), back on the GUI thread, allowing you to set the label to the new text including the result of the asynchronous operation.
Asynchronicity is not an absolute property - stuff is asynchronous to some other stuff, and synchronous to some other stuff. It only makes sense with respect to some other stuff.
Hopefully, now you can go back to your original code and understand the part you've misunderstood before. The solutions are multiple, of course, but they depend a lot on how and why you're trying to do what you're trying to do. I suspect you don't actually need to use Task.Run or await at all - the Parallel.ForEach already tries to distribute the CPU work over multiple CPU cores, and the only thing you could do is to make sure other code doesn't have to wait for that work to finish - which would make a lot of sense in a GUI application, but I don't see how it would be useful in a console application with the singular purpose of calculating that single thing.
So yes, you can actually use await for fire-and-forget code - but only as part of code that doesn't prevent the code you want to continue from executing. For example, you could have code like this:
Task<string> result = SomeHardWorkAsync();
Debug.WriteLine("After calling SomeHardWorkAsync");
DoSomeOtherWorkInTheMeantime();
Debug.WriteLine("Done other work.");
Debug.WriteLine("Got result: " + (await result));
This allows SomeHardWorkAsync to execute asynchronously with respect to DoSomeOtherWorkInTheMeantime but not with respect to await result. And of course, you can use awaits in SomeHardWorkAsync without trashing the asynchronicity between SomeHardWorkAsync and DoSomeOtherWorkInTheMeantime.
The GUI example I've shown way above just takes advantage of handling the continuation as something that happens after the task completes, while ignoring the Task created in the async method (there really isn't much of a difference between using async void and async Task when you ignore the result). So for example, to fire-and-forget your method, you could use code like this:
async void Fire(string filename)
{
var result = await ProcessFileAsync(filename);
DoStuffWithResult(result);
}
Fire("MyFile");
This will cause DoStuffWithResult to execute as soon as result is ready, while the method Fire itself will return immediately after executing ProcessFileAsync (up to the first await or any explicit return someTask).
This pattern is usually frowned upon - there really isn't any reason to return void out of an async method (apart from event handlers); you could just as easily return Task (or even Task<T> depending on the scenario), and let the caller decide whether he wants his code to execute synchronously in respect to yours or not.
Again,
async Task FireAsync(string filename)
{
var result = await ProcessFileAsync(filename);
DoStuffWithResult(result);
}
Fire("MyFile");
does the same thing as using async void, except that the caller can decide what to do with the asynchronous task. Perhaps he wants to launch two of those in parallel and continue after all are done? He can just await Task.WhenAll(Fire("1"), Fire("2")). Or he just wants that stuff to happen completely asynchronously with respect to his code, so he'll just call Fire("1") and ignore the resulting Task (of course, ideally, you at the very least want to handle possible exceptions).

Categories