Differences in async-await execution flows - c#

What's the difference between a top-down flow (where top is an API action and down is a Db transaction) using the following two approaches.
A full async-await flow
async Task X()
{
await Y();
}
async Task Y()
{
await Z();
}
async Task Z()
{
await session.CommitAsync();
}
Only the top-level method uses async-await.
async Task X()
{
await Y();
}
Task Y()
{
Z();
return Task.CompletedTask;
}
Task Z()
{
session.CommitAsync();
return Task.CompletedTask;
}
while the async instructs that Y should be executed async, what happens to Z ?

Edit: the question changed. General async answer below
The following Z will simply not wait for CommitAsync before returning. It's a fire and forget situation.
Task Z()
{
session.CommitAsync();
return Task.CompletedTask;
}
In an api controller situation this means that the web request would return to client before the session is committed.
Let's note this cannot be done for methods that return data.
The 2nd note is that there is no benefit here from returning a Task, and the return type could be changed to void (which may or may not help you reason about it).
Origjnal answer, still relevant
Let's say that in ZRealAsync calls await db.(...).ToListAsync() and ZPretendAsync calls ToList() and then returns Task.CompletedTask.
The difference is that a thread that happens to call ZRealAsync can be used to do other things after the query is sent to the database, and a thread which calls ZPretendAsync will not be able to be used for anything else until the result is obtained from the database, it will just wait; even if X is marked async and uses await.
If your web controllers call ZPretendAsync then the system won't be able to handle more concurrent requests than there are threads available, even if X is marked async and uses the await keyword. With ZRealAsync n threads can service more than n concurrent requests. Async makes a real difference, but only if it's real.

Related

What are differences between the 3 calls for async Func<Task<T>> in c#?

What are differences between the 3 calls inside method WhatDifferences?
Here is test code:
async Task WhatDifferences(Context context)
{
await ActionAsync(context, async x => await IsOddAsync(x).ConfigureAwait(false));
await ActionAsync(context, x => IsOddAsync(x));
await ActionAsync(context, IsOddAsync);
}
async Task<T> ActionAsync<T>(Context context, Func<Context, Task<T>> action)
{
return await action(context).ConfigureAwait(false);
}
async Task<bool> IsOddAsync(Context context)
{
return await Task.Run(() => context.Count++ % 2 == 1).ConfigureAwait(false);
}
class Context
{
public int Count { get; set; }
}
I'm trying to decide which one to use in my codebase and based on my knowledge all 3 behave the same.
The question is different with What's the method signature for passing an async delegate?
You may know my concern if I show more logic
async Task<T> ActionAsync<T>(Context context, Func<Context, Task<T>> action)
{
using (var transaction = new TransactionScope())
{
//do some async logic before action
var result = await action(context).ConfigureAwait(false);
//do other async validation logic after action
return result;
}
}
I'm trying to decide which one to use in my codebase and based on my knowledge all 3 behave the same.
In this specific instance, this is essentially true.
This one creates a delegate that refers to the IsOddAsync method:
await ActionAsync(context, IsOddAsync);
This one creates a method for the lambda expression and the delegate refers to that compiler-generated method:
await ActionAsync(context, x => IsOddAsync(x));
And this one does the same, but for an asynchronous lambda, so the compiler-generated method also has an async state machine:
await ActionAsync(context, async x => await IsOddAsync(x).ConfigureAwait(false));
In general, your question boils down to two questions:
Should I use method groups instead of lambdas? Yes, you should. There's no disadvantage to doing so, and it's a tiny bit more efficient, shorter code, without any impact on maintainability.
Should I elide async/await or keep the keywords in? This one is more nuanced.
Eliding async in this particular case is fine, because all the async lambda is doing is calling a single method and passing its parameter. There's no possibility of exceptions being thrown from the lambda before or after the call to IsOddAsync.
However, if your lambda is more complex - doing operations on x before passing it to IsOddAsync, or doing operations on the result, or using a using block, then you'd want to keep the async/await keywords for maximum maintainability. More information here.
await vs return Task
The difference between:
await ActionAsync(context, async x => await IsOddAsync(x).ConfigureAwait(false));
await ActionAsync(context, x => IsOddAsync(x));
In some cases you don't need the await (and also not the async of course)
Methods that perform asynchronous operations don't need to use await if:
There is only one asynchronous call inside the method
The asynchronous call is at the end of the method
Catching/handling exception that may happen within the Task is not necessary
See Returning a Task without await.
In that case you could return the Task intermediately.
Please note there is a small difference in behavior - depending on the implementation of IsOddAsync:
Important: Returning the Task instead of awaiting it, changes the exception behavior of the method, as it won't throw the exception inside the method which starts the task but in the method which awaits it.
As Gabriel Luci noted, with the current implementation of IsOddAsync (one call and an await), there is no difference in behavior.
x => IsOddAsync(x) vs IsOddAsync
The difference between
await ActionAsync(context, x => IsOddAsync(x));
await ActionAsync(context, IsOddAsync);
In the first one your are creating an anonymous (lambda) method with the parameter x. As IsOddAsync has also one parameter (with the same type), there is no need for the lambda method.
Please note you need the lambda if IsOddAsync has other parameters, e.g. and 2nd parameter, then you need the lambda. Example:
await ActionAsync(context, x => IsOddAsync(x, "mySecondParameter"));
In this case there is no difference in behavior, except the callstack when an exception in thrown inside.

Orleans single threaded nature not respected by ContinueWith

I have the following code (https://github.com/avinash0161/OrleansExperiments/tree/c0155b4b0c8c1bfe60aea8624f2cc83a52853dc7):
// Client code
Console.WriteLine("Client making a call");
var hashGenerator = client.GetGrain<IGrainA>(0);
hashGenerator.Call_A_ToTemp();
await Task.Delay(1000);
hashGenerator.Call_B_ToTemp();
// GrainA code
public async Task Call_A_ToTemp()
{
Console.WriteLine("Making call A to a fellow grain");
IGrainB grain = this.GrainFactory.GetGrain<IGrainB>(1);
grain.CallA().ContinueWith((t)=>
{
if(t.IsFaulted)
{
// Silo message timeout is 32s so t.IsFaulted is true
Console.WriteLine("Task Faulted");
Call_A_ToTemp();
}
});
}
public async Task Call_B_ToTemp()
{
Console.WriteLine("Making call B to a fellow grain");
IGrainB grain = this.GrainFactory.GetGrain<IGrainB>(1);
await grain.CallB();
}
// GrainB code
public async Task CallA()
{
Console.WriteLine("Call A came to GrainB");
await Task.Delay(34000); // more than timeout for the caller
}
public Task CallB()
{
Console.WriteLine("Call B came to GrainB");
return Task.CompletedTask;
}
The output for this code is:
Client making a call
Making call A to a fellow grain
Call A came to GrainB
Making call B to a fellow grain
Task Faulted <---------------- This comes after Call_B_ToTemp executes
Making call A to a fellow grain
As we can see, that Call_B_ToTemp executes before Call_A_ToTemp executes completely (ContinueWith part of Call_A_ToTemp is executed later). Is this expected and does it violate the single threaded nature of the grains?
When I replaced the code in Call_A_ToTemp() with:
public async Task Call_A_ToTemp()
{
Console.WriteLine("Making call A to a fellow grain");
IGrainB grain = this.GrainFactory.GetGrain<IGrainB>(1);
bool isSuccess = false;
while (! isSuccess)
{
try
{
await grain.CallA();
isSuccess = true;
} catch(TimeoutException){
Console.WriteLine("task faulted");
}
}
}
The code now preserves the single threaded nature and Call_B_ToTemp isn't called till all of ContinueWith part of Call_A_ToTemp() is executed. The console output is like:
Client making a call
Making call A to a fellow grain
Call A came to GrainB
Task Faulted
Making call A to a fellow grain
Can anyone please explain this? Is the single threaded nature violated when there is ContinueWith?
The single-threaded nature is not being violated. The compilation warnings in your project makes the source of the issue clear. In particular: This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.
The method async Task Call_A_ToTemp() never awaits the call to grain B. Instead, it returns immediately after issuing the call. Because the Task returned by Call_A_ToTemp() is immediately completed, another call is allowed to execute on the grain. Once grain.CallA() completes, the continuation (ContinueWith(...)) will execute on the grain's TaskScheduler as soon as possible (eg, while the grain is awaiting another call or sitting idle).
Instead, if the call was awaited or if async was removed from the method and the code changed to return the grain.CallA().ContinueWith(...) call then the expected behavior will be observed. I.e, changing the code to this will give you the expected result:
// removed 'async' here, since we're not awaiting anything.
// using 'async' is preferred, but this is to demonstrate a point about
// using ContinueWith and un-awaited calls
public Task Call_A_ToTemp()
{
Console.WriteLine("Making call A to a fellow grain");
IGrainB grain = this.GrainFactory.GetGrain<IGrainB>(1);
// Note the 'return' here
return grain.CallA().ContinueWith((t)=>
{
if(t.IsFaulted)
{
// Silo message timeout is 32s so t.IsFaulted is true
Console.WriteLine("Task Faulted");
Call_A_ToTemp();
}
});
}

Multiple hierarchy of task

I want to call a task which itself call a async method which inturn returna bool value.
I want to do something on the basis of that outcome.
I can get the data on outcome.Result.Result but this does not look good and I wish to have the output in outcome.Result.
I can not figure it out.
Can someone please guide.
private void OnValidated(ValidatedIntergrationEvent evt)
{
var outcome=Task.Factory.StartNew(() => mydata.UpdateValidated());
if (outcome.Result.Result)//This work fine but I think I need something to do so that outcome.Result gives my solution.
{ }
else { }
}
public async Task<bool> UpdateValidated()
{
var result= await Mediator.Send(new ValidatedEvent(this));
return result;
}
public async Task<bool> Handle(ValidatedEvent notification, CancellationToken cancellationToken)
{ //dO WORK
// return Task.FromResult(true);
return true;
}
Since UpdateValidated is already asynchronous, you should just call it directly to execute it. Things like Task.Factory.StartNew or Task.Run offer a way to put synchronous tasks on a new thread so that they can run asynchronously. So you should just call it directly:
private void OnValidated(ValidatedIntergrationEvent evt)
{
var outcome = mydata.UpdateValidated()
// Note: this WILL block, regardless of how you call the async function
var result = outcome.Result;
}
You should try to avoid using .Result though, as this will block synchronous functions until the asynchronous result is ready, and may even cause deadlocks. If the OnValidated is a standard event handler, you could make it asynchronous instead and await your task:
private async void OnValidated(ValidatedIntergrationEvent evt)
{
var result = await mydata.UpdateValidated()
}
But this make this event handler fire and forget which can be dangerous. So you should really try to change your code that you are truly running asynchronously when calling asynchronous code.
Finally, note that you can force the asynchronous task onto a separate thread using Task.Run. This is useful when the asynchronous call also does a lot on the CPU:
var outcome = Task.Run(() => mydata.UpdateValidated());
This looks very similar to your Task.Factory.StartNew() call but returns only a Task<bool> instead of your Task<Task<bool>>. This is because Task.Run has an overload that explicitly allows you to call asynchronous methods which makes Task.Run just pass on the result.

Looking for guidance to understand how asynchronous Programming with Async and Await works

i go through a msdn sample code where a function is called when button is clicked and when routine is called then Await keyword is used and function has async keyword used.
private async void StartButton_Click(object sender, RoutedEventArgs e)
{
int contentLength = await AccessTheWebAsync();
resultsTextBox.Text +=
String.Format("\r\nLength of the downloaded string: {0}.\r\n", contentLength);
}
async Task<int> AccessTheWebAsync()
{
HttpClient client = new HttpClient();
Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com");
DoIndependentWork();
string urlContents = await getStringTask;
return urlContents.Length;
}
void DoIndependentWork()
{
resultsTextBox.Text += "Working . . . . . . .\r\n";
}
When AccessTheWebAsync is called then await keyword is used, what does it mean?
When this function AccessTheWebAsync() will be executing then DoIndependentWork() function is called and i guess here control will be waiting until this function DoIndependentWork() is finished. Am I right?
again there is another statement called
string urlContents = await getStringTask;
why they use here await. if we do not use await here then what would happen?
Please guide me to understand the code that how it is working.
I have an intro blog post here, and the MSDN docs are also extremely good.
You can think of await as "pausing" the method (without blocking the thread) until the awaitable operation completes. When this happens, it returns a task that is not completed to the calling method, so it also has the option to await.
Here's a brief description about async/await methods.
Async Methods:
Caller is not necessarily blocked for the full execution of async
method
Possible return types
void: “fire-and-forget”
Task: allows to await termination of async method
Task<T>: allows to await termination and get result of type T
No ref or out parameter for async methods
Must again contain an await => Otherwise compile warning
await for Tasks
Await termination of a TPL task
Return result of task (if task with
result type)
Must only occur in async methods => Otherwise compile error
An async method is partly synchronous and partly asynchronous
Caller synchronously executes the method until a blocking await
Thereafter, the method rest is asynchronously executed
async & await Mechanism
Efficient
public async Task<int> GetSiteLengthAsync(string url)
{
HttpClient client = new HttpClient(); <= Sync
Task<string> download1 = client.GetStringAsync(url); <= Sync
string site1 = await download1; <= Async (Another thread)
return site1.Length; <= Async (Another thread)
}
Not sure if that simplier for you to understand that in the following way, but this is how it helped myself:
As you can see, the AccessTheWebAsync returns Task<int> but not just int.
If you would have called it without "await", you would just get the Task<int> object as its result. And could do anything further you want (manually) with that task: for instance, to wait until it finishes theTask.Wait(); and obtain the result of int in theTask.Result.
But await does all that instead of you and returns just int: Task<int> => int.
This is it.
from MSDN:
the await operator is applied to a task in an asynchronous method to suspend the execution of the method until the awaited task completes. The task represents ongoing work.await does not block the thread on which it is executing. Instead, it causes the compiler to sign up the rest of the async method as a continuation on the awaited task. Control then returns to the caller of the async method. When the task completes, it invokes its continuation, and execution of the async method resumes where it left off.
So when the compiler encounter
int contentLength = await AccessTheWebAsync();
it waits till the AccessTheWebAsync() task is complted
please take a look at this example C# Async,Await
All await does is blocks the thread until the result of an async operation returns.
Edit: sorry when I said block I should have said suspend, since blocking would prevent execution from continuing!
Edit2: As Alex pointed out - I should have probably said "execution is suspended" rather than the thread. Basically "Stuff happens until await returns but the point is it appears you are writing and executing synchronous code"
Since async operations have the potential to be take a while (e.g. web service calls), they tend to use callbacks to return a result.
If you have to handle callbacks in your code it can get a little messy, especially when waiting on multiple async tasks that are dependant on each other. Async/await and Task simplify the code so that you can write async code literally in the order you would read it.
e.g. example standard async code with callbacks:
public int CallSomeServiceAndReturnItsValue()
{
int result = 0;
WebService.SomeAsyncServiceCall((svcResult) => { result = svcResult.Value; });
return result;
}
and if you have multiple calls that need to be chained:
public int CallSomeServiceAndReturnItsValue()
{
int result = 0;
WebService.GetSomeIdentifier((svcResult) =>
{
var identifier = svcResult.Value;
WebService.GetResult(identifier, (anotherResult) =>
{
result = anotherResult.Value;
}
}
);
return result;
}
As you can see, it starts getting messy, the code doesn't really read in an order that feels natural. The alternative is to use callback methods instead of anonymous methods but still, the callback methods are far away from the code that called them and things can feel disjointed
The other alternative is of course async/await which is much clearer
public int CallSomeServiceAndReturnItsValue()
{
int identifier = await WebService.GetSomeIdentifier();
return await WebService.GetResult(identifier);
}

How to return type of Task<mytype> without running async

In my data access layer I'm attempting to create methods with return types of Task.
I cannot get the return type from the entity framework to return Task<List<MYtype>>
public static Task<List<ILeaf>> GetLeafs(int doorID)
{
using (var db = new StorefrontSystemEntities())
{
return db.proc_GetDoorLeafs(doorID).ToList<ILeaf>();
};
}
Is the only way to make this run correctly is to format the code like so:
public async static Task<List<ILeaf>> GetLeafs(int doorID)
{
return await Task.Run(() =>
{
using (var db = new StorefrontSystemEntities())
{
return db.proc_GetDoorLeafs(doorID).ToList<ILeaf>();
};
});
}
The reason I was asking is because I would like to give the option to run async, or am I not understanding this correctly?
If I can just return a Task then on the calling end I could give the option to await if I wanted to run async, but if i wanted to run synchronously I would just call the method as normal.
If I'm returning a Task do I always have to include the async keyword in the method signature?
Am I thinking about this the wrong way? If I've got a return type of Task then the method has the option of being called async or synchronously?
But, if I have async and Task in the method signature then the method runs async no matter what?
Thanks!
So to answer the literal question asked, you can just do this:
public static Task<List<ILeaf>> GetLeafs(int doorID)
{
return Task.Run(() =>
{
using (var db = new StorefrontSystemEntities())
{
return db.proc_GetDoorLeafs(doorID).ToList<ILeaf>();
};
});
}
That said, note that this isn't a particularly useful method. The idea of leveraging asynchronous programming is that you don't want to have a thread pool thread sitting there doing nothing but waiting on this IO operation. Ideally you'd leverage IO that is inherently asynchronous in nature; a method that itself naturally returns a task.
You aren't really providing value to consumers of your code by wrapping the blocking IO in a call to Task.Run. If they need that operation to be run in a background thread they can do so on their own, and then they'll know more precisely that it's not a naively asynchronous operation.
See Should I expose asynchronous wrappers for synchronous methods? for more information on the subject.
public static async Task<List<ILeaf>> GetLeafs(int doorID)
{
using (var db = new StorefrontSystemEntities())
{
var result = db.proc_GetDoorLeafs(doorID).ToList<ILeaf>();
return await Task.FromResult(result);
}
}

Categories