Using Async and Await in C# - c#

I'm trying to understand async and await, and I've got a few questions. In this example from Microsoft
async Task<int> AccessTheWebAsync()
{
// You need to add a reference to System.Net.Http to declare client.
HttpClient client = new HttpClient();
// GetStringAsync returns a Task<string>. That means that when you await the
// task you'll get a string (urlContents).
Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com");
// You can do work here that doesn't rely on the string from GetStringAsync.
DoIndependentWork();
// The await operator suspends AccessTheWebAsync.
// - AccessTheWebAsync can't continue until getStringTask is complete.
// - Meanwhile, control returns to the caller of AccessTheWebAsync.
// - Control resumes here when getStringTask is complete.
// - The await operator then retrieves the string result from getStringTask.
string urlContents = await getStringTask;
// The return statement specifies an integer result.
// Any methods that are awaiting AccessTheWebAsync retrieve the length value.
return urlContents.Length;
}
The method uses client.GetStringAsync, however, what happens if the method you're calling isn't an Async method? If I were calling for example, File.ReadAllLines(), how would I make that an Async call?
The method has a return type of Task<int>. Does any method that uses await, have to have a return type of Task<>? What if there is nothing to return?

The method uses client.GetStringAsync, however, what happens if the method you're calling isn't an Async method? If I were calling for example, File.ReadAllLines(), how would I make that an Async call?
Don't drive async from the "outside in"; rather, let it bubble up from the "inside out". In other words, if you want to make something asynchronous, you first find the lowest-level APIs that are asynchronous, then you make the calling method async.
The method has a return type of Task. Does any method that uses await, have to have a return type of Task<>? What if there is nothing to return?
Then the result type of the method should be Task.
Technically, async methods can return Task, Task<T>, or void. You should avoid async void; it should only be used for event handlers (or methods that are logically event handlers). Task<T> is a wrapper around a result type of T; this wrapper also includes information about any exceptions. Similarly, Task contains valuable information about exceptions (or successful completion).

You would call the appropriate Async method. If there isn't one, then it won't be truly asynchronous. You could "make" your own by wrapping it with Task.Run() but it really defeats the purpose of being async. This is fine in a desktop app, but it's a terrible idea to do in an ASP.NET/server scenario because you're creating more threads to handle the same functionality. (Too many threads means your throughput will suffer in server scenarios). All I/O (database ,file access) in .NET should have the appropriate Async() methods along with the standard blocking methods. For a deeper discussion on why this is a bad idea, see Stephen Taub's blog post on it.
Any method using the async/await pattern has to return a Task<>. This is because while the system is "await'ing", it will return a Task<>, which represents a future promise of the return type. The calling method can continue on if it wishes to other code, or it can stay await'ing your async method call and provide scalability benefits until the true underlying type has been returned from that async method.

If I were calling for example, File.ReadAllLines(), how would I make that an Async call?
You don't "make something" async, it has to be naturally so. Many operations are IO bound, such as a network call or accessing disk. There is no File.ReadAllLinesAsync, but you can write one yourself using a "lower-level" API such as FileStream.
Does any method that uses await, have to have a return type of Task<>? What if there is nothing to return?
No, it doesn't. A Task<T> is used when you have a return value from an asynchronous method. In your example, that value is a string. It is wrapped in a Task<> because a Task is a promise of work which will complete in the future. Awaiting on a Task<string> asynchronously waits until the async operation is done and that string is returned.

Related

Do I need to await a task in a wrapper method [duplicate]

This question already has answers here:
Why use async and return await, when you can return Task<T> directly?
(9 answers)
Closed 4 months ago.
I have a wrapper over Microsoft.Azure.Cosmos.Container class.
In some cases the only thing the wrapper does is calling the inner object's async method.
public Task<ItemResponse<T>> UpsertItemAsync<T>(T item, PartitionKey? partitionKey = null, ItemRequestOptions requestOptions = null, CancellationToken cancellationToken = default)
{
return _container.UpsertItemAsync<T>(item, partitionKey, requestOptions, cancellationToken);
}
What is the best practice in this case? To add await before or to return the inner object task as is?
David Fowler (ASP.NET Architect) has an excellent guidance.
I copy here the relevant part:
Prefer async/await over directly returning Task
There are benefits to using the async/await keyword instead of directly returning the Task:
Asynchronous and synchronous exceptions are normalized to always be asynchronous.
The code is easier to modify (consider adding a using, for example).
Diagnostics of asynchronous methods are easier (debugging hangs etc).
Exceptions thrown will be automatically wrapped in the returned Task instead of surprising the caller with an actual exception.
❌ BAD This example directly returns the Task to the caller.
public Task<int> DoSomethingAsync()
{
return CallDependencyAsync();
}
✅ GOOD This examples uses async/await instead of directly returning the Task.
public async Task<int> DoSomethingAsync()
{
return await CallDependencyAsync();
}
💡NOTE: There are performance considerations when using an async state machine over directly returning the Task. It's always faster to directly return the Task since it does less work but you end up changing the behavior and potentially losing some of the benefits of the async state machine.
It depends on what you want to achieve.
Here are the 2 case.
If you add an await in this wrapper function - The control stops there waiting for upsert to finish. Once everything is done then control came back to from where this wrapper methord is called
If you ignore an await - Now what happens is this control never wait to execute. It add's that async function to a thread pool using TPL which essentially runs it in background. But you never notice and the code never waits. It continues execution and immediately get back to where you called
2 things to note
If you await it, That line will return the Task result which can be
int, bool, string or whatever
If you ignore await, That line will
return a Task instead
There are many use cases for these 2 approaches.
If your caller requires output to continue, Use await here
If your
caller just calls it and can continue (Not dependent on this upsert,
Let it run in background) then don't use await
You have to add async to your wrapper declaration and await your inner object Task.. otherwise you will not be able to await your wrapper later in a caller context..

In .NET, are async methods exclusively those with the async keyword?

I've been learning about HttpClient (consuming API's in .NET in general), and therefore about async programming. I'm still pretty lost right now, so trying to clear some things up. One question I can't seem to find an answer to - are asynchronous methods implemented exclusively using the async keyword?
I understand that you could (theoretically) create synchronous methods using async programming, but how do you recognize that? For example, from this link and this example:
public string GetReleases(string url)
{
using (var httpClient = new HttpClient())
{
httpClient.DefaultRequestHeaders.Add(RequestConstants.UserAgent, RequestConstants.UserAgentValue);
var response = httpClient.GetStringAsync(new Uri(url)).Result;
return response;
}
}
The author says:
For the simplicity’s sake, I implemented it synchronously
But how do I recognize it is synchronous? Is it solely because the method is not defined with async Task, for example:
public async Task<string> GetReleases(string url)
Does that mean that in this HttpClient tutorial, this example is also not asynchronous:
// GET: Student
public ActionResult Index()
{
IEnumerable<StudentViewModel> students = null;
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:64189/api/");
//HTTP GET
var responseTask = client.GetAsync("student");
responseTask.Wait();
var result = responseTask.Result;
if (result.IsSuccessStatusCode)
{
var readTask = result.Content.ReadAsAsync<IList<StudentViewModel>>();
readTask.Wait();
students = readTask.Result;
}
else //web api sent error response
{
//log response status here..
students = Enumerable.Empty<StudentViewModel>();
ModelState.AddModelError(string.Empty, "Server error. Please contact administrator.");
}
}
return View(students);
}
So to sum up, my questions are:
Is async programming (in .NET), and async methods, implemented exclusively using async and void/Task/Task?
If not, how else, and if so, how do I recognize "true" asynchronous methods compared to synchronous methods implemented using asychronous principles (like the example above?)
Why then did the above examples use "sync through async", since from everything I've read everyone says to NEVER do that? Are they just bad examples, or for simplicity sake (even so, shouldn't "the correct way" > "simplicity"? Would it be ok to use this in situations where, e.g., I have very simple code and want to avoid threading/deadlock issues, since I'm not comfortable with async programming just yet?
how can I recognize truely async/sync methods?
You can't. Not really. You can spot methods that are potentially async, but little else can be learned without consulting documentation or the implementation of those methods.
So, you can examine a method's return type. If it's void, you don't know much. If it's Task, Task<T>, ValueTask<T> or any other awaitable type1, then the method may be asynchronous. But bear in mind, the method signature may be fixed because the type inherited the method from a base class or it's implementing an interface; So whilst the method has the potential to be async, the actual implementation of that method may be completely synchronous.
Or, the method may have the potential to be asynchronous but may have particular control flows which lead to it behaving synchronously2. These may be e.g. that if certain conditions are true, the method already has the answer, so it returns it straight away. Otherwise it goes off and does something async - as one example.
If the return type isn't awaitable and it's non-void, all you can actually reason about the method is that, at the point at which it returns, it's supplied some value for that return type3. There's no way to reason about any other work that may have been started by that method - only that if it's done something like that, it doesn't intend for you to be able to discover when that work has completed.
If you're looking at the implementation of a method and asking yourself "is this implementation async" then the important thing is to work out what this code makes happen after control is returned back to the caller.
When is control returned back to the caller?
When we hit a return
When we hit an await, maybe
When we hit an await, we only return control back to the caller4 if the awaitable that we're awaiting isn't complete yet. So we have to find out where that awaitable came from and, if it came from calling another method, we have to start again from scratch in considering what that method does.
If the method contains awaits then it's usually safest to say that it's potentially async - but bear in mind the above possibilities about already completed awaitables and early returns.
If it's not async/await, what else might it have done? Well, if it's working with Tasks, it may have created one or more of those tasks to represent it's ongoing work. It may have scheduled more code to run via ContinueWith.
If it's not working with Tasks directly, hasn't called something else that is potentially async, hasn't cause a new Thread to be created and isn't needlessly obfuscated, it's probably synchronous.
Would it be ok to use this in situations where, e.g., I have very simple code and want to avoid threading/deadlock issues, since I'm not comfortable with async programming just yet?
The sync over async patterns shown in the examples in your question are more prone to deadlocks than working with async/await. Why? Because they block the current thread waiting for other things to happen. But the current thread or resources that it has locked may be special - and the actual async tasks that it's invoked may need to gain access to that same thread/resource before they can complete. Classic deadlock.
1Awaitable is one of a number of places where C# uses "duck typing". If there's a method available (instance or extension) called GetAwaiter that returns a type with the right shape, it's awaitable. So despite the fact that you'll probably never see one, be aware that custom awaitables are possible in the language.
2"Hot path" optimizations come to mind.
3And out/ref parameters. Of course, if it has those it won't be an async method implemented via the async/await keywords but it may still have some asynchronous behaviour.
4If we've already yielded control back to the caller during an earlier await, we won't return control back to the caller at later awaits, but we'll be returning it to "something" that isn't our code.
If a method returns a Task or Task<T> (with exception to void in case of event handler) then it can be awaited and hence it can be asynchronous. async keyword is only an indication that it may await somewhere for another awaitable. Based on the control flow, async may return without actually awaiting anything.
Asynchronous programming is not a new thing, it has existed in many forms like callbacks, Invokes etc.
Examples you have provided are not using async await pattern properly. Microsoft has provided naming convention (Async Suffix) and Task<T>, Task as types for async programming. So if you see some method returning Task<T> or Task and Method name has suffix "Async" then you can consider it asynchronous. Although suffix thing is not required by compiler, it helps in differentiating it from its synchronous counterpart. (Read vs ReadAsync)
They are bad examples, those action should be marked as async and all the Async methods should be awaited for result. There can be an exception in some console program where main can't be async.
Please read Stephen Cleary blog on async await
An asynchronous method in C# can return void, Task or Task<T>, where void should be avoided in general because it cannot be awaited.
As a convention asynchronous methods should be called DoSomethingAsync()
The async keyword, however, is an implementation detail and does not belong to the API. This keyword is only required if you use an await in the method body. But that need not be the case. You could simply delegate to another asynchronous method, without the need to mark the method as async and using an await.
So 'true' asynchronous methods should be recognizable by the Async suffix of the method name, however, you can't be sure the implementor actually uses naturally asynchronous operations or even runs synchronously some parts or the whole method.
In the example he made the method synchronously by putting .Result at the end of GetStringAsync

Are there new Task object created when we chain the ContinueWith calls?

Consider a situation when the method returns a chain of tasks, like this one(I was working mainly with .net 3.5, so the example uses ContinueWith, but the question is the same for await):
static Task UnwrappedTask()
{
Task<Task> t = TestStr().ContinueWith( (
return GetTaskFromString(s).ContinueWith(
// returns a task
});
});
return t.Unwrap();
}
static async Task GetTaskFromString(string str)
{
await Task.Delay(3000);
}
static async Task<string> TestStr()
{
await Task.Delay(3000);
return "res";
}
Is there a new Task object created every time we return from ContinueWith(), or does the compiler reuse the instance somehow? I am interested in how the Value type Task.Result behaves in this scenario: is it copied all those times, or does the wrapper Task class provide an efficient way of transporting it to the outermost method?
ContinueWith will always create a new task. It can't possibly do anything else. The whole design of the method is that ContinueWith takes an existing Task, executes some arbitrary method after it has finished, and produces a new result. The result of ContinueWith isn't ever going to be identical to the task it is a continuation of, so it can't just re-use it. It is, by design, not mutating the task it's adding a continuation to (at least in any externally visible way, technically storing the continuations to fire is an internal mutation of the Task).

Is it useful to mark a method async when it only awaits at the return statement? [duplicate]

This question already has answers here:
Why use async and return await, when you can return Task<T> directly?
(9 answers)
Closed 2 years ago.
Only the last line of the method below is using 'await', just before the method returns, so doesn't this mean that method is basically synchronous and should just be called "Get()" without the async modifier and the suffix Async?
public virtual async Task<TEntity> GetAsync(Guid id)
{
// some more code here
return await _dbSet.FindAsync(id);
}
doesn't this mean that method is basically synchronous
No. It's asynchronous. You're probably thinking of sequential (progressing from one thing to the next), not synchronous (blocking the current thread). An await will pause the method (sequentially) but not block the thread (asynchronously). For more information, see my async intro.
without the async modifier
While you could elide the async/await keywords, I would recommend that you do not. This is because // some more code here may throw an exception. I cover this and other considerations in my blog post on eliding async and await.
and the suffix Async?
No, that suffix is appropriate for any method that returns an awaitable (e.g., Task). So, even if you elide the async and await, it's still returning a task that should be awaited, so it should still have the Async suffix.
You can think of it this way: the Async suffix is part of the API interface. The async keyword is an implementation detail. They often go together, but not always.
Its a matter of opinion. Generally the naming convention is anything that returns Task or Task<T> has a suffix of Async.
Your example above though would be better written like this so you do not have the extra overhead of the async wrapper. This is because you do not need to await the result in that method. The consumer of the method would then await the result if it used it directly.
public virtual Task<TEntity> GetAsync(Guid id, params Expression<Func<TEntity, object>>[] includeProperties))
{
// some more code here
return _dbSet.FindAsync(id);
}
await doesn't block. It awaits asynchronously for an operation to complete. That means that the original thread is released while awaiting. In a desktop application, this means that the UI thread is released while waiting eg for an HTTP or database call to finish.
When that operation completes, execution is returned to the original thread (for desktop applications).
As it is, you can simplify your code by removing the async and await keywords and returning the Task immediatelly. The code doesn't do anything with the results of the operation, so it doesn't need to await for it to finish. This will be done by the caller of the method:
public virtual Task<TEntity> GetAsync(Guid id)
{
// some more code here
return _dbSet.FindAsync(id);
}
The real asynchronous operation in this code is FindAsync. The async keyword is just syntactic sugar that allows you to use the await keyword. If you don't need to await, you don't need the async keyword either
There are many cases where suffixing every async method with Async is simply redundant. If your method returns a Task or Task<T>, and its purpose is to get data from a database or another network resource, then of course it runs asynchronously. The compiler will also almost always give you an error if you forget to await something. With that in mind, there are some good reasons to suffix async methods with Async:
The method runs asynchronously but does not return a Task
There is an alternative other method by the same name that runs synchronously
Forgetting an await in calling code is unlikely to be caught by the compiler
Suffixing a method name with Async is meant to indicate that the method runs asynchronously, which this method does. Whether it does so using async/await or directly returns another Task is an implementation detail. Imagine you were reviewing some code calling the method that forgets to use await. Which of these makes the error more apparent?
var item1 = _example.Get(itemId1);
var item2 = _example.GetAsync(itemId2);
Based on nothing else, there's no reason to believe there's anything wrong with the first line. The second line will at least raise some eyebrows.

Does async really enable callers to await?

MSDN says:
If you specify that a method is an async method by using an Async or async modifier, you enable the following two capabilities... The marked async method can itself be awaited by methods that call it.
But another page gives this example:
private async Task SumPageSizesAsync()
{
// To use the HttpClient type in desktop apps, you must include a using directive and add a
// reference for the System.Net.Http namespace.
HttpClient client = new HttpClient();
// . . .
Task<byte[]> getContentsTask = client.GetByteArrayAsync(url);
byte[] urlContents = await getContentsTask;
// Equivalently, now that you see how it works, you can write the same thing in a single line.
//byte[] urlContents = await client.GetByteArrayAsync(url);
// . . .
}
Here we see it call a function GetByteArrayAsync which is not equipped with the async keyword, and yet the caller is able to await on the result.
Is MSDN wrong when it says that the async modifier enables callers to await?
From the caller's perspective, what's the difference between a function that returns Task<T>, and the same function marked as async?
Is MSDN wrong when it says that the async modifier enables callers to await?
No. It does allow callers to await as it rewrites your method to return a Task/Task<T>. But it isn't the only way to do so. Any method that returns an awaitable (e.g. Task<bool>, YieldAwaitable) enables the callers to await.
From the caller's perspective, what's the difference between a function that returns Task<T>, and the same function marked as async?
If it's implemented correctly, there shouldn't be any difference. The async and await keywords are a way for the compiler to help you write asynchronous code. But they are not necessary. You can (and you always could have) write asynchronous code without them.
Take Task.Delay for example. It creates a task, sets a timer, configures the timer to complete the task after some time and returns the task. It doesn't use async-await and it doesn't need to. But by returning a task it allows the caller to await it.
In fact, a lot of the task-returning methods in the .NET framework don't use async-await internally as they are the "root" asynchronous methods. They return a task but don't have a task to await themselves.
Do do not await a function, you await a Task or a Task<T> that a function returns1. In any examples where you see await client.GetByteArrayAsync(url) there is a hidden implicit Task<byte[]> that gets "passed" between the client.GetByteArrayAsync(url) and the await.
You question is similar to asking "How does the + work when you do
int result = 1 + 2;
vs when you do
int two = 2;
int result = 1 + two;
The documentation states it is for adding two numbers together, but I am not adding two numbers in the 2nd example I am adding a number and a variable."
1: It is a little more completed than that, but for 99% of the time just think of it that way.
From async/await faq (emphasis mine):
What does the “async” keyword do when applied to a method?
When you mark a method with the “async” keyword, you’re really telling
the compiler two things:
You’re telling the compiler that you want to be able to use the “await” keyword inside the method (you can use the await keyword if
and only if the method or lambda it’s in is marked as async). In doing
so, you’re telling the compiler to compile the method using a state
machine, such that the method will be able to suspend and then resume
asynchronously at await points.
You’re telling the compiler to “lift” the result of the method or any exceptions that may occur into the return type. For a method that
returns Task or Task, this means that any returned value or
exception that goes unhandled within the method is stored into the
result task. For a method that returns void, this means that any
exceptions are propagated to the caller’s context via whatever
“SynchronizationContext” was current at the time of the method’s
initial invocation.
So, think of it as a syntactic sugar over plain old asynchronous .NET model: more compiler checks, less code, and completely indifferent from the caller perspective (caller either awaits the result inside async method or uses other TPL primitives, or even blocks).
Actually, if you check the source code of the GetByteArrayAsync method, it is simply a wrapper over GetContentAsync method constructing the resulting Task with TaskCompletionSource and continuation-passing style.
private Task<T> GetContentAsync<T>(Uri requestUri, HttpCompletionOption completionOption, T defaultValue,
Func<HttpContent, Task<T>> readAs)
{
TaskCompletionSource<T> tcs = new TaskCompletionSource<T>();
GetAsync(requestUri, completionOption).ContinueWithStandard(requestTask =>
{
if (HandleRequestFaultsAndCancelation(requestTask, tcs))
{
return;
}
HttpResponseMessage response = requestTask.Result;
if (response.Content == null)
{
tcs.TrySetResult(defaultValue);
return;
}
try
{
readAs(response.Content).ContinueWithStandard(contentTask =>
{
if (!HttpUtilities.HandleFaultsAndCancelation(contentTask, tcs))
{
tcs.TrySetResult(contentTask.Result);
}
});
}
catch (Exception ex)
{
tcs.TrySetException(ex);
}
});
return tcs.Task;
}
An async modifier allows you to use the await keyword within that method. Any Task can be awaited within a method marked async -- the Task represents an ongoing activity that may or may not already be complete when it is returned to the caller.
As far as I can tell it's not being awaited. The Task is.
The marked async method can itself be awaited - that's for methods. A Task doesn't need that in order to be awaitable (which is what you're doing in await getContentsTask).
This also answers part 2 - The difference is that the one that returns Task and is not marked async cannot be awaited. Which is what MSDN says in the quoted text.
(I might be wrong, of course.)

Categories

Resources