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.
Related
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.
I've been trying to understand async/await and Task in C# but have been failing spectacularly despite watching youtube videos, reading documentation and following a pluralsight course.
I was hoping someone might be able to help answer these slightly abstract questions to help my brain out.
1.Why do they say that async/await enables an 'asynchonrous' method when the async keyword on it's own does nothing and the await keyword adds a suspension point? Isn't adding a suspension point forcing the method to act synchronously, i.e. finish the task marked by the await before moving on.
2.Apparently you are not supposed to use async void except for event handlers, so how do you call an async method normally? It seems that in order to call an async method by using the await keyword, the method/class that is calling it itself needs to be marked as async. All the examples I've seen have 'initiated' an async void method with an event handler. How would you 'escape' this wrapping of async/await to run the method?
3.
public async Task SaveScreenshot(string filename, IWebDriver driver)
{
var screenshot = driver.TakeScreenshot();
await Task.Run(() =>
{
Thread.Sleep(2000);
screenshot.SaveAsFile(filename, ScreenshotImageFormat.Bmp);
Console.WriteLine("Screenshot saved");
});
Console.WriteLine("End of method");
}
Relating back to 1. this looks like a synchronous method. Execution pauses when it gets to Task.Run, therefore Console.WriteLine("End of method"); will not be executed until the task is finished. Maybe the whole method itself will be executed asynchronously at the point it is triggered in the code? But relating back to 2, you need to call this with an await otherwise you get the message 'Because this call is not awaited..' therefore adding an await will cause that execution point to be synchronous and so on and so.
Any help understanding this would be much appreciated.
Isn't adding a suspension point forcing the method to act synchronously, i.e. finish the task marked by the await before moving on.
No, the word you're thinking of is "sequential", not "synchronous". await results in asynchronous sequential code. "Sequential" meaning "one at a time"; "synchronous" meaning "blocking until completed".
how do you call an async method normally?
Using await.
How would you 'escape' this wrapping of async/await to run the method?
Ideally, you don't. You go async all the way. Modern frameworks (including ASP.NET MVC, Azure Functions / WebJobs, NUnit / xUnit / MSTest, etc) all allow you to have entry points that return Task. Less-modern frameworks (including WinForms, WPF, Xamarin Forms, ASP.NET WebForms, etc) all allow async void entry points.
So, ideally you do not call asynchronous code from synchronous code. This makes sense if you think about what asynchronous code is: the entire point of it is to not block the calling thread, so if you block the calling thread on asynchronous code, then you lose all the benefits of asynchronous code in the first place.
That said, there are rare situations where you do need to treat the code synchronously. E.g., if you are in the middle of a transition to async, or if you are constrained by a library/framework that is forcing your code to be synchronous and won't work with async void. In that case, you can employ one of the hacks in my article on brownfield async.
Your understanding is pretty good :). The main point you seem to be missing is that "asynchronous" methods in .NET mean methods that can stop execution without blocking the calling thread.
As you pointed out in (1), the async keyword basically enables the use of await and requires the return type to be void or Task/Task<T>. await just instructs the current method to suspend execution until the task is complete.
What you are missing here is that it suspends just the current method. It does not block the thread the method was executing on. This is important in cases like the UI thread of a WPF application. Suspend method execution and everything keeps running, block the thread and the application stops responding.
You usually want your async calls to go all the way to the top (like an event handler), this allows the most flexibility and prevents deadlock situations. However; you can wait for a Task returning method to complete with Wait:
someAsyncMethod.Wait()
Or get the return value:
var result = someAsyncMethod.Result;
Note that both of these are synchronous and block the calling thread. Doing this can cause deadlock if the async task is waiting for some other work on the calling thread to complete.
The above should answer your question in (3); the method itself appears to execute synchronously (this is the magic of await/async) but the task doesn't block the calling thread.
It is asynchronous because you don't have to wait the method to return. In your code, you may call the async method and save the task in a variable. Continue doing something else. Later, when the method result is needed, you await the response (task).
// Synchronous method.
static void Main(string[] args)
{
// Call async methods, but don't await them until needed.
Task<string> task1 = DoAsync();
Task<string> task2 = DoAsync();
Task<string> task3 = DoAsync();
// Do other stuff.
// Now, it is time to await the async methods to finish.
Task.WaitAll(task1, task2, task3);
// Do something with the results.
Console.WriteLine(task1.Result);
Console.ReadKey();
}
private static async Task<string> DoAsync()
{
Console.WriteLine("Started");
await Task.Delay(3000);
Console.WriteLine("Finished");
return "Success";
}
// Output:
// Started
// Started
// Started
// Finished
// Finished
// Finished
// Success
I googled a lot and for the moment the only async implementation I found (including MSDN site) is the following:
public async void Foo()
{
...
await StreamReader.ReadAsync();
...
}
So in all the cases they use some method which is already async. And this is not what I need.
Let's say that I have a heavy method that does something:
public void DoSomthing()
{
...
}
And there is method where I call this DoSomething:
public void MajorMethod()
{
DoSomething();
}
I want to make DoSomething ayncthonous and call it.
The only solution I see would be the following one:
public Task MajorMethod()
{
return Task.Run(()=>DoSomething());
}
But I read some comments that it's not really the async. So how can I make DoSomething async?
If the MajorMethod has no other things to do other than calling the DoSomething, your code is fine.
But if you need to do other stuff after calling to DoSomething, then mark MajorMethod as async, and use await before Task.Run
public async Task MajorMethod()
{
await Task.Run(()=>DoSomething());
//stuff in here will executed after DoSomething completed
}
Examples from MSDN: Asynchronous programming
or just google c# async
You should be clear about the role async/await play in the Task Asynchronous Pattern. Making an async method does not parform an operation asynchronously just like that. Marking an existing method async will not magically perform everything in there asynchronously. Its main effect is that now you are allowed to use await within the method (I read that it even was discussed if the async keyword was necessary at all; it was added to avoid a breaking change when a local variable in existing methods would be named await).
await also does not provide asynchrony by itself, it provides a way to synchronize to another asnychronous method and yield while the other operation is still running. You can await another async method, but unless somwhere down the chain there is an actual Task running in another thread, the async method might even return synchronously.
In consequence this means that you need an operation that runs asynchronously first (such as a DB query, file access, network communication) and from there you create a chain of async methods that await the previous method.
Now in your case, when you have a computationally intensive method that does not wait for external resources, you can choose to perform the operation asynchronously. Since modern CPUs usually have more than one core at your disposal, you can increase both, performance and application responsiveness like that. The method would not be async, since it does not await anything:
void DoSomething()
{
//...
}
Task DoSomethingAsync() {
return Task.Run(DoSomething);
}
All callers of DoSomethingAsync can now use await to synchronize with this operation running in the background (note the change in return type to Task to allow callers to await):
async Task MajorMethod() {
//...
await DoSomethingAsync();
//...
}
This would allow callers of MajorMethod to synchronize with it. What you can also do is to do stuff in MajorMethod while DoSomethingAsync is running (and still await to allow callers to do even more parallel operations):
async Task MajorMethod() {
//This part will run before DoSomethingAsync
//...
Task doSomethingTask = DoSomethingAsync();
//This part is executed at the same time as DoSomethingAsync
//...
await doSomethingTask; //Here the caller can do more operations while DoSomething is running
//This part will be executed after DoSomethingAsync has finished
//...
}
This form of acquiring a task, doing something and only then awaiting the task has to be done somewhere in the chain, otherwise you have no benefit from the asynchronous operation. Even though this might be an overgeneralization, since synchronization can happen in more subtle ways, for example with a custom synchronization context. But as far as your question is concerned, you should go with: There is an actual task on one end and something that is done after the async call, but before the await on the other end.
EDIT: from OP's comment, the goal is
non-blocking background task so that the rest remain responsive
Say I have a function like this:
void OnFrameSampleAcquired(VideoCaptureSample sample)
{
//Some code here
//Here I want to introduce an Asynchrnous process
ProcessAsynchronously(_latestImageBytes);
//some more code here
}
In the point commented, I want to introduce a call to an asynchronous function.
Now, I can not modify OnFrameSampleAcquired (meaning I can not make it "async").
How can I do this?
I am thinking
async void ProcessAsynchronously(byte[] image)
{
await Process1(image);
await Process2(image);
// ...
}
or async Task ProcessAsynchronously(byte[] image)
where ProcessX are also declared as async
Is this a good approach?
Thanks for any insight, since my practical experience with asynchronous processing is very few.
EDITED included all suggestions from the comments and added some background.
Background & insights
Converting one function to async won't be enough to make the whole process non-blocking. To achieve what you want, the whole processing path (call stack) should be converted to non-blocking. One blocking method on your call stack is enough to render the whole process blocking. Non-blocking does not necessarily mean async, as some of the examples below will show.
There are two steps involved in converting a method into async:
Change the signature to return Task. This will allow your callers track status and outcome of your method.
Add async keyword to the signature. This will allow await-ing other async methods in the body of your method.
CPU-bound vs IO-bound tasks
Note that even when you await for a method, it doesn't necessarily mean that you immediately release the thread back to your caller. The method being await-ed will release the thread back to you only as soon as it in turn begins await-ing for an IO-bound operation. Your thread will still block while the await-ed method performs CPU-bound operations before the first time it is await-ing for an IO-bound operation.
For example:
async Task MyAsyncMethod()
{
Thread.Sleep(5000); // equivalent to CPU-bound operations
}
await MyAsyncMethod(); // will block for 5 seconds
On the other hand,
async Task MyAsyncMethod()
{
await Task.Delay(5000); // equivalent to IO-bound operations
}
await MyAsyncMethod(); // will return immediately
And the workaround if you have CPU-bound tasks but still don't want to block the caller thread:
async Task MyAsyncMethod()
{
await Task.Yield(); // this does the magic
Thread.Sleep(5000); // equivalent to CPU-bound operations
}
await MyAsyncMethod(); // will return immediately thanks to Task.Yield()
What to do in your case
Since I'm not sure why you cannot change OnFrameSampleAcquired signature to async, I will suggest several different options.
Option 1
The simplest and the truly asynchronous approach would be this:
async Task OnFrameSampleAcquired(VideoCaptureSample sample)
{
//Some code here
//Here I want to introduce an Asynchrnous process
await ProcessAsynchronously(_latestImageBytes);
//some more code here -- provided it is either async or non-blocking!
}
async Task ProcessAsynchronously(byte[] image)
{
await Process1(image);
await Process2(image);
// ...
}
If all of the methods on your processing path look like these, you have a properly implemented non-blocking background job.
Option 2
If you're absolutely unable to change the signature OnFrameSampleAcquired, there is a workaround. You can instead invoke the rest of the processing asynchronously, as suggested by #Fildor:
public void OnFrameSampleAcquired(VideoCaptureSample sample)
{
//Some code here
//Here I want to introduce an Asynchrnous process
ProcessAsynchronously(_latestImageBytes).ContinueWith(task => {
// this runs on a different thread after ProcessAsynchronously is completed
// some more code here
});
// return without blocking
}
Here you win on both sides: first, you don't have to change the signature of OnFrameSampleAcquired; second, OnFrameSampleAcquired is now a non-blocking method.
Option 3
If you cannot change your signature because you must implement an interface like this:
public interface ISomeInterface
{
void OnFrameSampleAcquired(VideoCaptureSample sample);
// ... other members
}
then you can add the async keyword to your method and still comply with the interface:
async void OnFrameSampleAcquired(VideoCaptureSample sample)
{
//Some code here
//Here I want to introduce an Asynchrnous process
await ProcessAsynchronously(_latestImageBytes);
//some more code here
}
ISomeInterface x; // initialized elsewhere
x.OnFrameSampleAcquired(/*....*/); // the same as await, but no error handling
The drawback of this option is that the callers cannot track nor the status of the task (still running or completed?), neither its outcome (completed or threw exception?). You will probably have to wrap the entire body of OnFrameSampleAcquired in a try/catch, and write an exception to log.
Option 4
Technically, you can also invoke an async ProcessAsynchronously from a non-async OnFrameSampleAcquired using Wait on a Task, but it won't achieve your goal of having a non-blocking background task. The Wait() will block the thread until the async processing is done:
void OnFrameSampleAcquired(VideoCaptureSample sample)
{
//Some code here
//Here I want to introduce an Asynchrnous process
ProcessAsynchronously(_latestImageBytes).Wait();
//some more code here
}
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).