In regards to async operations, I understand it's bad practice to use Task.Run
in your implementation if you are exposing your code in a library to be consumed elsewhere as you should leave such decisions to the caller of your library. That information can be found in the 'duplicate' questions here. But that is not what I am asking. I am seeking clarification for our own code which is in a WPF desktop app and will never be exposed as a library for others to consume.
Additionally, our task takes 1-2 minutes of intense CPU-processing if that makes any difference.
My question is in our particular case, does it make sense to use a background thread to make our non-async function async, or do we simply make our function async, then call it with await?
Also, the long-running function doesn't do any async/await stuff itself. It's purely a linear, CPU-intensive task, and I don't care where it's run, only that its return value (and the progress) are reported back to the main UI.
That is what I'm seeking clarification on.
I'm using .NET 5.0 with C#9 in a WPF desktop app directly (i.e. this code is not in a library to be shared with others) if it matters.
Here's some (updated for clarity!) sample code illustrating this...
public static void Main() {
// Local function to start the import
// Note: I read I should be using `async void` and not 'async Task' here since
// this is a top-level async statement and I understand you need this for proper
// exception handling. Is that correct?
async void startImport(){
Debug.WriteLine($"Import starting... IsBackground: " +
$"{Thread.CurrentThread.IsBackground}");
var progress = new Progress<string>(message =>
Debug.WriteLine($"Progress Update: {message}"));
// Toggle the comments on these lines and the line defining
// CPUIntenseSequentialImport to try it with and without Task.Run()
var result = await Task.Run(() => CPUIntenseSequentialImport(progress));
//var result = await CPUIntenseSequentialImport(progress);
Debug.WriteLine($"Finished! The result is {result} - IsBackground: " +
$"{Thread.CurrentThread.IsBackground}");
}
startImport();
Debug.WriteLine($"Import started... IsBackground: " +
$"{Thread.CurrentThread.IsBackground}");
}
// Can you just mark this as async, then use await on it and not need Task.Run(),
// or because it's a long-running task, should you NOT mark it with async, and
// instead use Task.Start() so it gets its own thread from the pool?
static public int CPUIntenseSequentialImport(IProgress<string> progress) {
//static async public Task<int> CPUIntenseSequentialImport(IProgress<string> progress) {
Thread.Sleep(1000);
progress.Report($"First part of import done - IsBackground: " +
$"{Thread.CurrentThread.IsBackground}");
Thread.Sleep(1000);
progress.Report($"Next part of import done - IsBackground: " +
$"{Thread.CurrentThread.IsBackground}");
Thread.Sleep(1000);
progress.Report($"Final part of import done - IsBackground: " +
$"{Thread.CurrentThread.IsBackground}");
return 44;
}
When run as-is, you get this (Note the updates are not reporting from a background thread)...
Import starting... IsBackground: False
Import started... IsBackground: False
Progress Update: First part of import done - IsBackground: False
Progress Update: Next part of import done - IsBackground: False
Progress Update: Final part of import done - IsBackground: False
Finished! The result is 44 - IsBackground: False
...but when you swap the commented/uncommented lines, you get this (Note the updates are reporting from a background thread)...
Import starting... IsBackground: False
Import started... IsBackground: False
Progress Update: First part of import done - IsBackground: True
Progress Update: Next part of import done - IsBackground: True
Progress Update: Final part of import done - IsBackground: True
Finished! The result is 44 - IsBackground: False