Proper approach on async/await method including Lambda - c#

I would like to show two paradigms about async programming and listen to your comments.
A.
Let's say you have created a method like the following in a library to use it from your GUI clients.
public async Task<TestObject> DoSomeWork(string aParam1, object aParam2)
{
TestObject testObj = new TestObject();
...fill in params to testObj...
await MethodCallAsync(testObj);
....do other work synchronous.....
....continue fill testObj properties...
await Task.Delay(1000) // just a delay for no reason
...continue synchronous work.....
return testObj;
}
Ok, but this will chop my GUI context into small calling pieces, right? or I don't know if from the moment you declare a method async it will create a Task for all the operations inside?
If yes then great, no problem we can just declare it async and move on with our lives.
Lets say no and I would like to take the following approach so I won't disturb the GUI at all until my whole method call finishes and take the result so do something in my calling method.
B.
Another approach would be.
public async Task<TestObject> DoSomeWork(string aParam1, object aParam2)
{
TestObject testObj = new TestObject()
..fill state params....
return await Task.Factory.StartNew((state) =>
{
//But now I need to do async/await in here
// is it a good practice to async await lambdas?
// async/await practices say it's ok as long sas it is not becoming async void
// which in our case is not.
await MethodCallAsync(testObj);
....do other work synchronous.....
....continue fill state properties...
await Task.Delay(1000) // just a delay for no reason
...continue synchronous work.....
return state; // Our state and TestObject to examine after completion
}, testObj);
}
Our problem now it's not only if we should asyncify the lambda, say you do it, it the will return a Task<Task<TestObject>> and definitely we don't want that.
You should call this up in the pipeline, most probably your GUI class.
private async void SomethingClickedOrTouched(object sender, EventArgs e)
{
await RunThisAsyncToDoYourJob();
}
private async Task RunThisAsyncToDoYourJob()
{
TestObject testObj = await myObject.DoSomeWork("param1", anotherObject);
}
It just bugs me a little and I really want into detail with async programming.
So, is A paradigm the correct approach anyway, and use the B paradigm only when the Task lambda inside code is completely synchronous?
Thank you in advance.
Regards.

The proper way to write an async method is to use ConfigureAwait(continueOnCapturedContext: false) whenever you don't need to resume on the captured context. This is normally done for all "library" code.
this will chop my GUI context into small calling pieces, right?
Yes (since you're not using ConfigureAwait).
or I don't know if from the moment you declare a method async it will create a Task for all the operations inside?
Yes, async will create a Task that represents the async method. However, the fact that there is a Task does not mean that its code is running on a background thread.
it the will return a Task<Task<TestObject>> and definitely we don't want that.
I'd like to know where everyone is getting the idea of using Task.Factory.StartNew for asynchronous tasks. Task.Run is superior if you want to run code on a background thread.
I have an async intro on my blog that you may find helpful.

Related

How to not wait for a long running async task method?

I know it's not a good practice to use an async void. But what if I don't want to wait for a result of a long running task?
I have a scenario where I need to insert some values to the database and return a result. But I don't need to wait to finish all the insert before returning an instance of an object.
If you look at the code below, there's a method that initializes the DataService. But during the initialization part it needs to insert code description and headers to the database. I would like to return the dataService and I don't care if the code description and headers are finished inserting.
async Task<DataService> InitializeAsync()
{
_dataService = new DataService();
await _dataService.InsertCodeDescriptionAsync();
await _dataService.InserHeadersAsync();
return _dataService;
}
I think I can do that by changing InsertCodeDescriptionAsync and InsertHeadersAsync to be an async void function. But that's not good according to some articles I read. So what would be the best thing to do in this scenario?
Update:
The goal is to initialize the dataService and do the insert in the background.
Well my suggested answer is two-fold:
Simple answer: If you don't need to await a task, then don't await it.
But the consequences will be that the execution contexts of your main code and your not awaited tasks will diverge and if an exception happens in either of the methods you'll never know in your code. I suppose you call the two methods for a reason and they do something that'll eventually be needed by your code but not right away?
If so then I would suggest to still use await even if you don't need the methods to complete right away. This will however guarantee that the methods have completed at some point and the performance impact is often minimal, especially in a multi-threading scenario, since that's when the async magic kicks in and frees a lot of CPU time while waiting.
If you want to have both speed and reliability you could do something like
(DataService, Task) InitializeAsync()
{
_dataService = new DataService();
var t = Task.WhenAll(_dataService.InsertCodeDescriptionAsync(), _dataService.InserHeadersAsync());
return (_dataService, t);
}
which will give you the dataService right away but also a Task that you can use to await the completion of your initialization methods when you need them to be completed.
don't await the tasks you don't want to wait for. something like below will work for you.
Task<DataService> InitializeAsync()
{
_dataService = new DataService();
_dataService.InsertCodeDescriptionAsync();
_dataService.InserHeadersAsync();
return Task.FromResult(_dataService);
}
You could get rid of async and await altogether:
DataService Initialize()
{
_dataService = new DataService();
var fireAndForgetTask1 = _dataService.InsertCodeDescriptionAsync();
var fireAndForgetTask2 = _dataService.InsertHeadersAsync();
return _dataService;
}
This way you avoid any compiler warnings, and communicate your intent to ignore the results of the tasks to future maintainers of your code.

Where does async and await end? Confusion

I have a program which has no purpose but to help me understand how async and await works. It's a console application which parses XML and waits for a name to be returned, either the surname or the first name. Here is the code:
static void Main(string[] args)
{
Task<string> name = GetFirstParsedName();
name.Wait();
if (name.IsCompleted)
{
Console.WriteLine(name.Result);
}
Console.ReadLine();
}
static async Task<string> GetFirstParsedName()
{
string xmlSnippet = #"<person>
<FirstName>Chamir</FirstName>
<Surname>Bodasing</Surname>
<Gender>Male</Gender>
<Nationality>South African</Nationality></person>";
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(xmlSnippet);
XmlParser xmlParser = new XmlParser();
Task<string> t_GetFirstName = xmlParser.GetFirstName(xmlDoc);
Task<string> t_GetSurname = xmlParser.GetSurname(xmlDoc);
Task<string> t_firstReturnedName = await Task.WhenAny(new Task<string>[] { t_GetFirstName, t_GetSurname });
string firstReturnedName = await t_firstReturnedName;
return firstReturnedName;
}
static async Task<string> GetFirstName(XmlDocument personXml)
{
string firstName = personXml.SelectSingleNode("//FirstName").InnerText;
await Task.Delay(5000);
return firstName;
}
static async Task<string> GetSurname(XmlDocument personXml)
{
string surname = personXml.SelectSingleNode("//Surname").InnerText;
await Task.Delay(1);
return surname;
}
It seems like it only makes sense to use the async method when you don't have to return a value to a main method. Unless it means setting a global class property which can then be accessed. If not, in order to await the method, all methods need to be async which in turn means that the return type must be Task<T>. It seems like it never ends unless I explicitly have to write the following code (as in above main method):
Task<string> name = GetFirstParsedName();
name.Wait();
if (name.IsCompleted)
{
Console.WriteLine(name.Result);
}
Is my understanding correct at all? I have to use the result property to get the value here and from reading up about this, it seems that this is not the best practice.
It seems like it only makes sense to use the async method when you don't have to return a value to a main method. Unless it means setting a global class property which can then be accessed.
Your async methods can return Task<T> to return a value to its caller. Asynchronous methods do not work very well if they depend on side effects (i.e., setting properties / globals); they work much better if your code is more pure (i.e., taking parameters and returning results).
If not, in order to await the method, all methods need to be async which in turn means that the return type must be "Task" . It seems like it never ends
This is why one of the central principles of async is "async all the way". In most applications, this is exactly what you should do. Eventually, the "async chain" generally ends in an async void event handler (for UI apps) or an async Task<T> entry point (for ASP.NET apps). Console apps are unusual since they do require an explicit Wait()/Result or equivalent in their Main method.
After all, the whole point of async is to free up the calling thread. If the next method up the call stack blocks that same thread until the async code is complete, well, that was a whole lot of work for no benefit...
It seems like it only makes sense to use the async method when you don't have to return a value to a main method.
Why do you say that? It makes sense to use an async method where-ever you have a naturally asynchronous operation ongoing. No matter if that operation has a return value or doesn't.
in order to await the method, all methods need to be async which in turn means that the return type must be "Task" . It seems like it never ends
That's correct. Async spreads in your code like a plage, from the bottom to the top of your stack. It usually reaches the highest calling place in your stack (be it a console Main method or a UI event handler). That's the advantage of using async, it allows you to asynchronously wait an operation while freeing the calling thread. This can help, for example, if you have a WebAPI endpoint which needs to handle a large amount of requests concurrently. If you spend most of your time querying a database, you can free that calling thread in the meanwhile to serve more requests.
Is my understanding correct at all? I have to use the result property to get the value here and from reading up about this, it seems that this is not the best practice.
You have to use the Result property because a console application is a special case, where Main cant be marked as async (unless you're using ASP.NET CoreCLR console app). If this was a UI event handler or an ASP.NET action, you'd properly await the async call.
Well, async keyword let's compiler know that your method is going to execute series of asynchronous calls that should most likely be awaited but should not block the main (or UI) thread.
To help you understand async-await a little bit, here is some simple example:
Consider the scenario, when user clicks 'Save' button on WinForm's app, and some UI operation is started asynchronously in different Thread.
The code is :
private Task SomeUIOperation()
{
// ui operation
return Task.Run(() =>
{
this.Invoke(new Action(() => this.BackColor = Color.Aquamarine));
Thread.Sleep(10000);
this.Invoke(new Action(() => this.BackColor = Color.Gray));
});
}
private async void button1_Click(object sender, EventArgs e)
{
await SomeUIOperation();
// some other stuff
}
If we do not use async-await here UI thread will become unresponsive for 10 seconds.
It's an example of how you usually use async-await, you use it when you want some piece of code to be executed only when asynchronous operation is completed and in the same time you do not want the main thread to be blocked.
And console application is not the best project type for testing and learning Async-Await

Can ConfigureAwait(false) in a library lose the synchronization context for the calling application?

I've read the advice many times from people smarter than me, and it has few caveats: Always use ConfigureAwait(false) inside library code. So I'm fairly certain I know the the answer, but I want to be 100%. The scenario is I have a library that thinly wraps some other asynchronous library.
Library code:
public async Task DoThingAsyc() {
// do some setup
return await otherLib.DoThingAsync().ConfigureAwait(false);
}
Application code:
// need to preserve my synchronization context
await myLib.DoThingAync();
// do I have my context here or did my lib lose it?
No.
The capturing of the SynchronizationContext happens on await. ConfigureAwait configures the specific await.
If the application calls a library's async method and awaits it the SC is captured on the spot regardless of what happens inside the call.
Now, because the async method's synchronous part (which is the part before the first await) is executed before a task is returned to be awaited, you can mess around with the SynchronizationContext there, but ConfigureAwait doesn't do that.
In your specific example you seem to be returning the result of ConfigureAwait from the async method. That can't happen because ConfigureAwait returns the ConfiguredTaskAwaitable struct. If however we change the method return type:
public ConfiguredTaskAwaitable DoThingAsyc()
{
return otherLib.DoThingAsync().ConfigureAwait(false);
}
Then awaiting it will indeed affect the calling code's await behavior.
Example from http://blogs.msdn.com/b/pfxteam/archive/2012/01/20/10259049.aspx
... logically you can think of the following code:
await FooAsync();
RestOfMethod();
as being similar in nature to this:
var t = FooAsync();
var currentContext = SynchronizationContext.Current;
t.ContinueWith(delegate
{
if (currentContext == null)
RestOfMethod();
else
currentContext.Post(delegate { RestOfMethod(); }, null);
}, TaskScheduler.Current);
which means you should have your context back after the await myLib.DoThingAync(); call.
If used inconsistently in the logical chain of async calls, ConfigureAwait(false) may add redundant context switches (which usually means redundant thread switches). This may happen in the presence of synchronization context, when some async calls on the logical stack use ConfigureAwait(false) and some don't (more here).
You still should use ConfigureAwait(false) in your code, but you may want to peek into the 3rd party code you're calling and mitigate any inconsistency with something like this:
public async Task DoThingAsyc() {
// do some setup
await Task.Run(() => otherLib.DoThingAsync()).ConfigureAwait(false);
// do some other stuff
}
This would add one extra thread switch, but might potentially prevent many others.
Moreover, if you're creating a really thin wrapper like you showed, you may want to implement it like below, without async/await at all:
public Task DoThingAsyc() {
// do some setup
return otherLib.DoThingAsync();
}

How(and why) can I avoid returning a void on these async methods?

EDIT: So it seems having the method return void instead of task means that exceptions are propagated on the wrong(unexpected?) context.
However, my IDE (Xamarin) is still kicking up a fuss on the line in my constructor where I call AttemptDatabseLoad()
"The statement is not awaited and execution of current method
continues before the call is completed. Consider using 'await'
operator or calling 'Wait' method"
Why is it kicking up this fuss? Surely the entire purpose of using an async method is precisely so that the program continues execution on the Main thread.
I've read a fair bit on async and await as I need to have some async data loading for an app i'm making. I've read in loads of places that it's bad practice to have an async method return void (excepting in cases of firing events) and I understand the reason why it can be good to keep a handle on the Task.
However, I can't see anything logically wrong with what I've written below so my question is twofold: Why is my current code poor practice? How should it be re-written?
private const int MAX_CONNECTION_ATTEMPTS = 10;
private int ConnectionAttempts = 0;
//Constructor
public DataLoader()
{
//First load up current data from local sqlite db
LoadFromLocal();
//Then go for an async load from
AttemptDatabaseLoad();
}
public async void AttemptDatabaseLoad()
{
while(ConnectionAttempts < MAX_CONNECTION_ATTEMPTS){
Task<bool> Attempt = TryLoad ();
bool success = await Attempt;
if (success) {
//call func to load data into program memory proper
}else{
ConnectionAttempts++;
}
}
}
//placeholder for now
public async Task<bool> TryLoad()
{
await Task.Delay(5000);
return false;
}
Constructor are meant to bring an object to it's fully constructed structure once initialized. On the other hand, async methods and constructors don't play well together, as a constructor is inherintly synchronous.
The way to get around this problem is usually to expose an initialization method for the type, which is itself async. Now, you let the caller initialize the object fully. Note this will require you to monitor the actual initialization of the method.
Async shines when you need scale. If you don't expect this to be an IO bottleneck in your application, perhaps consider using synchronous methods instead. This will give you the benefit of actually fully initializing your object once the constructor finishes execution. Although, I don't think I would initiate a call to a database via a constructor anyway:
public async Task InitializeAsync()
{
LoadFromLocal();
await AttemptDatabaseLoadAsync();
}
public async Task AttemptDatabaseLoadAsyncAsync()
{
while(ConnectionAttempts < MAX_CONNECTION_ATTEMPTS)
{
Task<bool> Attempt = TryLoad ();
bool success = await Attempt;
if (success)
{
//call func to load data into program memory proper
}
else
{
ConnectionAttempts++;
}
}
}
And call it:
var dataLoader = new DataLoader();
await dataLoader.InitializeAsync();
I understand the reason why it can be good to keep a handle on the Task.
So it seems having the method return void instead of task means that exceptions are propagated on the wrong(unexpected?) context.
One of the reasons it's good to have a Task is that you can use it to retrieve the results of the asynchronous method. And by "results", I don't just mean the return value - I mean exceptions, too. The Task represents the execution of that asynchronous method.
When an exception escapes an async Task method, it's placed on that returned task. When an exception escapes an async void method, there's no obvious place for it to go, so the actual behavior is to raise it directly on the SynchronizationContext that was current at the beginning of the async void method. This sounds odd, but it's specifically designed to emulate exceptions escaping event handlers.
Of course, if your async void method isn't an event handler (like this example), then the behavior seems very odd and surprising.
Why is it kicking up this fuss? Surely the entire purpose of using an async method is precisely so that the program continues execution on the Main thread.
I think you're misunderstanding the warning message. Since the Task represents the execution of that method, to ignore it is an error 99.9% of the time. By ignoring it, your code is saying that it doesn't care when the async method completes, what its return value is (if any), and whether or not it throws exceptions. It's extremely rare for code to not care about any of these.
How should it be re-written?
I have a blog post on how to do "async constructors". My favorite approach is the asynchronous factory method:
//Constructor
private DataLoader()
{
//First load up current data from local sqlite db
LoadFromLocal();
}
public static async Task<DataLoader> CreateAsync()
{
var result = new DataLoader();
await result.AttemptDatabaseLoadAsync();
return result;
}
However, since you're using this in a UI application, I suspect you'll eventually run into a situation where you want to call asynchronous code from your ViewModel constructor. Asynchronous factories are great for helper code (like DataLoader), but they don't work for ViewModels because the VMs need to be created immediately - the UI needs to show something now.
At the UI layer, you have to first initialize your UI to some kind of a "loading" state, and then update it to a "normal" state once the data has arrived. I prefer to use asynchronous data binding for this, as described in my MSDN article.
You can just change return type to Task (non-generic) and don't return "explicitly" from async method. The reasons why it's better to use void only on top-level functions can be found here: async/await - when to return a Task vs void?
So, it's mainly about recovery from exception in your async-void method. I hope it will help.
EDIT: One more thing - because I didn't notice that you're calling it from constructor. Please check also this answer: https://stackoverflow.com/a/23051370/580207 and this blog post: http://blog.stephencleary.com/2013/01/async-oop-2-constructors.html
Why is my current code poor practice?
The callers of DataLoader() constructor might experience the following issues:
Code instantiating DataLoader class is not aware that load operation is still in progress after DataLoader() returns, so it cannot use the data retrieved by async AttemptDatabaseLoad().
There is no way to discover when the loaded data becomes available.
It cannot be composed into a larger asynchronous operation.
A suggested change is to store the task returned by async method in a property so that the caller can use it to wait until load is completed, or compose it into an asynchronous method.
class DataLoader
{
public DataLoader ()
{
//First load up current data from local sqlite db
LoadFromLocal();
//Then go for an async load from
this.Completion = AttemptDatabaseLoadAsync();
}
async Task AttemptDatabaseLoadAsync()
{
while(ConnectionAttempts < MAX_CONNECTION_ATTEMPTS){
Task<bool> Attempt = TryLoad ();
bool success = await Attempt;
if (success) {
//call func to load data into program memory proper
}else{
ConnectionAttempts++;
}
}
}
public Task Completion
{
get; private set;
}
}
Usage:
var loader = new DataLoader();
loader.Completion.Wait();
or:
async Task SomeMethodAsync()
{
var loader = new DataLoader();
await loader.Completion;
}

Difference between calling an async method and Task.Run an async method

I have a method in my view model
private async void SyncData(SyncMessage syncMessage)
{
if (syncMessage.State == SyncState.SyncContacts)
{
this.SyncContacts();
}
}
private async Task SyncContacts()
{
foreach(var contact in this.AllContacts)
{
// do synchronous data analysis
}
// ...
// AddContacts is an async method
CloudInstance.AddContacts(contactsToUpload);
}
When I call SyncData from the UI commands and I'm syncing a large chunk of data UI freezes. But when I call SyncContacts with this approach
private void SyncData(SyncMessage syncMessage)
{
if (syncMessage.State == SyncState.SyncContacts)
{
Task.Run(() => this.SyncContacts());
}
}
Everything is fine. Should not they be the same?
I was thinking that not using await for calling an async method creates a new thread.
Should not they be the same? I was thinking that not using await for
calling an async method creates a new thread.
No, async does not magically allocate a new thread for it's method invocation. async-await is mainly about taking advantage of naturally asynchronous APIs, such as a network call to a database or a remote web-service.
When you use Task.Run, you explicitly use a thread-pool thread to execute your delegate. If you mark a method with the async keyword, but don't await anything internally, it will execute synchronously.
I'm not sure what your SyncContacts() method actually does (since you haven't provided it's implementation), but marking it async by itself will gain you nothing.
Edit:
Now that you've added the implementation, i see two things:
I'm not sure how CPU intensive is your synchronous data analysis, but it may be enough for the UI to get unresponsive.
You're not awaiting your asynchronous operation. It needs to look like this:
private async Task SyncDataAsync(SyncMessage syncMessage)
{
if (syncMessage.State == SyncState.SyncContacts)
{
await this.SyncContactsAsync();
}
}
private Task SyncContactsAsync()
{
foreach(var contact in this.AllContacts)
{
// do synchronous data analysis
}
// ...
// AddContacts is an async method
return CloudInstance.AddContactsAsync(contactsToUpload);
}
What your line Task.Run(() => this.SyncContacts()); really does is creating a new task starting it and returning it to the caller (which is not used for any further purposes in your case). That's the reason why it will do its work in the background and the UI will keep working. If you need to (a)wait for the task to complete, you could use await Task.Run(() => this.SyncContacts());. If you just want to ensure that SyncContacts has finished when you return your SyncData method, you could using the returning task and awaiting it at the end of your SyncData method. As it has been suggested in the comments: If you're not interested in whether the task has finished or not you just can return it.
However, Microsoft recommend to don't mix blocking code and async code and that async methods end with Async (https://msdn.microsoft.com/en-us/magazine/jj991977.aspx). Therefore, you should consider renaming your methods and don't mark methods with async, when you don't use the await keyword.
Just to clarify why the UI freezes - the work done in the tight foreach loop is likely CPU-bound and will block the original caller's thread until the loop completes.
So, irrespective of whether the Task returned from SyncContacts is awaited or not, the CPU bound work prior to calling AddContactsAsync will still occur synchronously on, and block, the caller's thread.
private Task SyncContacts()
{
foreach(var contact in this.AllContacts)
{
// ** CPU intensive work here.
}
// Will return immediately with a Task which will complete asynchronously
return CloudInstance.AddContactsAsync(contactsToUpload);
}
(Re : No why async / return await on SyncContacts- see Yuval's point - making the method async and awaiting the result would have been wasteful in this instance)
For a WPF project, it should be OK to use Task.Run to do the CPU bound work off the calling thread (but not so for MVC or WebAPI Asp.Net projects).
Also, assuming the contactsToUpload mapping work is thread-safe, and that your app has full usage of the user's resources, you could also consider parallelizing the mapping to reduce overall execution time:
var contactsToUpload = this.AllContacts
.AsParallel()
.Select(contact => MapToUploadContact(contact));
// or simpler, .Select(MapToUploadContact);

Categories

Resources