I have a few questions about asynchronous programming - c#

I use the following code and it works, but I'm not sure if it is the best/recommanded way to do asynchronous programming.
For example, is the following code necessary or can I call UpdateUsername() without writing this code?
NewUsername();
public async void NewUsername()
{
await UpdateUsername();
}
I use "await" twice in my code, is it necessary to use it twice?
Is it always necessary to use "await" before some code that is marked with async, like the "await" before "PlayFabClientAPI.UpdateUserTitleDisplayNameAsync"?
private async Task UpdateUsername()
{
var resultupdatee = await PlayFabClientAPI.UpdateUserTitleDisplayNameAsync(new UpdateUserTitleDisplayNameRequest()
{
DisplayName = "NewName"
});
if (resultupdatee.Error != null)
{
// Handle error if any
Console.WriteLine(resultupdatee.Error.GenerateErrorReport());
}
else
{
Console.WriteLine("User display name updated");
}
}
When gets the line "int Count = 10;" executed? Is it possible that this line gets excuted before "await PlayFabClientAPI.UpdateUserTitleDisplayNameAsync" finished?
I want that "int Count = 10;" is only then executed after the code UpdateUsername() is finished.
NewUsername();
int Count = 10;

Based on that NewUsername returns void, it does not support awaiting, so there is no need to make it an asynchronous method.
public void NewUsername()
{
UpdateUsername();
}
But you need to ensure that int Count = 10 executes after the asynchronous task is done, we cannot let NewUsername return void, otherwise there is nothing to await.
Based on your code I assume that there is no further operation after UpdateUsername, so there is no need for NewUsername to be a async method
public Task NewUsername()
{
return UpdateUsername();
}
But if there is, you need
public async Task NewUsername()
{
await UpdateUsername();
//Operations after UpdateUsername is done.
}
As long as NewUsername returns Task, you can use await to ensure int Count = 10; executes after everything is done.
//Must be in an async function
await NewUsername();
int Count = 10;
As you can see, if there is some operation in a function A that needs to execute after another asynchronous function B is done, then function A needs to be asynchronous. In other words, asynchronous function is transitive. An asynchronous callee makes the caller asynchronous, unless you don't need to ensure the sequence of execution or you block the thread to wait synchronously.
Conclusion, there are 3 ways to do after calling an asynchronous function:
Waiting asynchronously, which is to await it to add operations after the callee is done. This makes the caller asynchronous.
Waiting synchronously, which is to call Wait method on the returned Task value to block the current thread for the completion. This is not recommanded for it makes the asynchronous callings meaningless.
Waiving the returned Task value of the asynchronous callee or the callee returning void, which is not to go ahead executing without waiting for the completion of the callee.

Related

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

Do I need to mark all methods in the flow with async and await

I have a public method which calls multiple private methods. Do I have to mark all methods in the flow with async and await or just the method with time consuming work?
No, you don't have to mark all procedures async, only those procedures where you call other async functions. You probably do this already when calling .NET functions
async Task DoIt(...)
{
// call async function, wait until finished
string txt = await ReadMyTextFile();
// call non-async function
string reversed = txt.Reverse();
// call async function, wait until finished
await WriteMyTextFile(reversed);
}
If you call an async function, you can be assured that somewhere in this function there is an await. In fact, your compiler will warn you if you forget to await somewhere inside your procedure.
If a thread that is executing the procedure meets the await, the thread won't wait idly until the awaited task is finished, but goes up its call stack to see if the caller of the procedure is not awaiting, and continues processing that procedure until is meets an await. Go up the call stack again, continue processing until the await, etc.
Task<int> ReadNumber(FileStream in
{
// start fetching data from a database, don't await yet
Task<int> taskFetchCustomerCount = FetchCustomerCountAsync();
// once the await is met in FetchCustomerCountAsync, the thread will start doing this
// also don't need the result yet. Don't await
Task<MonthlyReport> taskReadReport = ReadMonthlyReportAsync();
// once the await is met in ReadMonthlyReportAsync the thread will continue doing this
// this is a non-async function
string reportPeriod = GetReportPeriod();
// by now, we need the result from the database. Start waiting for it
int customerCount = await taskFetchCustomerCount;
// if the database is not finished yet, the thread goes up the call stack to see
// if the caller can continue
// after a while the database has fetched the result, we can continue
string customerCountLine =
$"At the end of {reportPeriod} the company had {customerCount} customers.";
// now we need the result from the Report reading:
MonthlyReport report = await taskReadReport;
// call a non-async function
report.SetCustomerCountLine(customerCountLine);
// save the report. Nothing to do anymore, so await until saving completed
await report.SaveAsync();
}

Inside a loop,does each async call get chained to the returned task using task's continuewith?

The best practice is to collect all the async calls in a collection inside the loop and do Task.WhenAll(). Yet, want to understand what happens when an await is encountered inside the loop, what would the returned Task contain? what about further async calls? Will it create new tasks and add them to the already returned Task sequentially?
As per the code below
private void CallLoopAsync()
{
var loopReturnedTask = LoopAsync();
}
private async Task LoopAsync()
{
int count = 0;
while(count < 5)
{
await SomeNetworkCallAsync();
count++;
}
}
The steps I assumed are
LoopAsync gets called
count is set to zero, code enters while loop, condition is checked
SomeNetworkCallAsync is called,and the returned task is awaited
New task/awaitable is created
New task is returned to CallLoopAsync()
Now, provided there is enough time for the process to live, How / In what way, will the next code lines like count++ and further SomeNetworkCallAsync be executed?
Update - Based on Jon Hanna and Stephen Cleary:
So there is one Task and the implementation of that Task will involve
5 calls to NetworkCallAsync, but the use of a state-machine means
those tasks need not be explicitly chained for this to work. This, for
example, allows it to decide whether to break the looping or not based
on the result of a task, and so on.
Though they are not chained, each call will wait for the previous call to complete as we have used await (in state m/c, awaiter.GetResult();). It behaves as if five consecutive calls have been made and they are executed one after the another (only after the previous call gets completed). If this is true, we have to be bit more careful in how we are composing the async calls.For ex:
Instead of writing
private async Task SomeWorkAsync()
{
await SomeIndependentNetworkCall();// 2 sec to complete
var result1 = await GetDataFromNetworkCallAsync(); // 2 sec to complete
await PostDataToNetworkAsync(result1); // 2 sec to complete
}
It should be written
private Task[] RefactoredSomeWorkAsync()
{
var task1 = SomeIndependentNetworkCall();// 2 sec to complete
var task2 = GetDataFromNetworkCallAsync()
.ContinueWith(result1 => PostDataToNetworkAsync(result1)).Unwrap();// 4 sec to complete
return new[] { task1, task2 };
}
So that we can say RefactoredSomeWorkAsync is faster by 2 seconds, because of the possibility of parallelism
private async Task CallRefactoredSomeWorkAsync()
{
await Task.WhenAll(RefactoredSomeWorkAsync());//Faster, 4 sec
await SomeWorkAsync(); // Slower, 6 sec
}
Is this correct? - Yes. Along with "async all the way", "Accumulate tasks all the way" is good practice. Similar discussion is here
When count is zero, new task will be created because of await and be returned
No. It will not. It will simply call the async method consequently, without storing or returning the result. The value in loopReturnedTask will store the Task of LoopAsync, not related to SomeNetworkCallAsync.
await SomeNetworkCallAsync(); // call, wait and forget the result
You may want to read the MSDN article on async\await.
To produce code similar to what async and await do, if those keywords didn't exist, would require code a bit like:
private struct LoopAsyncStateMachine : IAsyncStateMachine
{
public int _state;
public AsyncTaskMethodBuilder _builder;
public TestAsync _this;
public int _count;
private TaskAwaiter _awaiter;
void IAsyncStateMachine.MoveNext()
{
try
{
if (_state != 0)
{
_count = 0;
goto afterSetup;
}
TaskAwaiter awaiter = _awaiter;
_awaiter = default(TaskAwaiter);
_state = -1;
loopBack:
awaiter.GetResult();
awaiter = default(TaskAwaiter);
_count++;
afterSetup:
if (_count < 5)
{
awaiter = _this.SomeNetworkCallAsync().GetAwaiter();
if (!awaiter.IsCompleted)
{
_state = 0;
_awaiter = awaiter;
_builder.AwaitUnsafeOnCompleted<TaskAwaiter, TestAsync.LoopAsyncStateMachine>(ref awaiter, ref this);
return;
}
goto loopBack;
}
_state = -2;
_builder.SetResult();
}
catch (Exception exception)
{
_state = -2;
_builder.SetException(exception);
return;
}
}
[DebuggerHidden]
void IAsyncStateMachine.SetStateMachine(IAsyncStateMachine param0)
{
_builder.SetStateMachine(param0);
}
}
public Task LoopAsync()
{
LoopAsyncStateMachine stateMachine = new LoopAsyncStateMachine();
stateMachine._this = this;
AsyncTaskMethodBuilder builder = AsyncTaskMethodBuilder.Create();
stateMachine._builder = builder;
stateMachine._state = -1;
builder.Start(ref stateMachine);
return builder.Task;
}
(The above is based on what happens when you use async and await except that the result of that uses names that cannot be valid C# class or field names, along with some extra attributes. If its MoveNext() reminds you of an IEnumerator that's not entirely irrelevant, the mechanism by which await and async produce an IAsyncStateMachine to implement a Task is similar in many ways to how yield produces an IEnumerator<T>).
The result is a single Task which comes from AsyncTaskMethodBuilder and makes use of LoopAsyncStateMachine (which is close to the hidden struct that the async produces). Its MoveNext() method is first called upon the task being started. It will then use an awaiter on SomeNetworkCallAsync. If it is already completed it moves on to the next stage (increment count and so on), otherwise it stores the awaiter in a field. On subsequent uses it will be called because the SomeNetworkCallAsync() task has returned, and it will get the result (which is void in this case, but could be a value if values were returned). It then attempts further loops and again returns when it is waiting on a task that is not yet completed.
When it finally reaches a count of 5 it calls SetResult() on the builder, which sets the result of the Task that LoopAsync had returned.
So there is one Task and the implementation of that Task will involve 5 calls to NetworkCallAsync, but the use of a state-machine means those tasks need not be explicitly chained for this to work. This, for example, allows it to decide whether to break the looping or not based on the result of a task, and so on.
When an async method first yields at an await, it returns a Task (or Task<T>). This is not the task being observed by the await; it is a completely different task created by the async method. The async state machine controls the lifetime of that Task.
One way to think of it is to consider the returned Task as representing the method itself. The returned Task will only complete when the method completes. If the method returns a value, then that value is set as the result of the task. If the method throws an exception, then that exception is captured by the state machine and placed on that task.
So, there's no need for attaching continuations to the returned task. The returned task will not complete until the method is done.
How / In what way, will the next code lines like count++ and further SomeNetworkCallAsync be executed?
I do explain this in my async intro post. In summary, when a method awaits, it captures a "current context" (SynchronizationContext.Current unless it is null, in which case it uses TaskScheduler.Current). When the await completes, it resumes executing its async method within that context.
That's what technically happens; but in the vast majority of cases, this simply means:
If an async method starts on a UI thread, then it will resume on that same UI thread.
If an async method starts within an ASP.NET request context, then it will resume with that same request context (not necessarily on the same thread, though).
Otherwise, the async method resumes on a thread pool thread.

does last async call in async method require await?

I can't understand if await statement is required when async method call is the last call in my async method. E.g.
public async Task CallAsync(byte[] data)
{
await Call1Async(data);
Call2Async(data);
}
public async Task Call1Async(byte[] data)
{
...
}
public async Task Call2Async(byte[] data)
{
...
}
The above would compile but with a warning "consider applying await to this method". But I think it would be waste of resources to apply await for the last call in the method.
At the same time, if I use return Call2Async(data); instead of just Call2Async(data);, the warning would go away. This indicates await is not actually required in such situation.
But this only works for methods which have a return value (i.e. Task<T> rather than just Task). I need this for methods without return values. Is there any way to do the same for value-returning methods?
I.e. I need to somehow return Task object returned by Call2Async to the caller of CallAsync and I can't use return statement in CallAsync explicitly as my methods don't have return values. Of course, I can adjust them all to return values (e.g. true) but it would not be an elegant solution.
P.S. If I have the only async call in my method, I just don't add 'async' to the method signature, and it works ('return' statement not required). But if the method contains more than one async call, I need to have 'async' modifier to be able to await for the first call 'await Call1Async(data)'. And adding 'async' modifier makes the compiler require 'return' to return Task object to the caller (and this works only for methods with return values). That's what I'm trying to overcome.
In the following method:
public async Task CallAsync(byte[] data)
{
await Call1Async(data);
Call2Async(data);
}
Control from the method returns after beginning Call2Async. That is, if you were to await CallAsync(data), it would finish before Call2Async ends. This is probably not what you intended. This method will only finish when both calls are complete:
public async Task CallAsync(byte[] data)
{
await Call1Async(data);
await Call2Async(data);
}
You can see the difference in these example outputs (I implemented the two async calls to simply print a start, delay for a second, and then print an end).
void Main()
{
Console.WriteLine("Main start");
CallAsync(null).Wait();
Console.WriteLine("Main end");
}
The method without the second await prints:
Main start
Call1Async start
Call1Async end
Call2Async start
Main end
Call2Async end
And with the second await:
Main start
Call1Async start
Call1Async end
Call2Async start
Call2Async end
Main end
This implementation also has a problem:
public Task CallAsync(byte[] data)
{
Call1Async(data);
return Call2Async(data);
}
It kicks off both async calls at the same time, but then returns control when Call2Async completes, whether Call1Async is complete or not. Again, this is probably not what you intended.
async keyword indicates that the method is asynchronous and than it will contain the await keyword in it.
I don't understand why you have multiple asynchronous methods?
Consider the following example :
async void MyMethod()
{
Task<object> result = MyWorkAsync();
MyIndependentOtherWork();
object res = await result;
}
Calling MyWorkAsync is like creating a thread "toto" to execute the method (i.e Thread.Start(MyWorkAsyn))
The await keyword is like making a join form the current thread to the thread "toto" and than getting the result of "toto", and in the mean time you get your other independent work to execute on the current thread

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

Categories