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..
Related
Here's what I mean:
public Task<SomeObject> GetSomeObjectByTokenAsync(int id)
{
string token = repository.GetTokenById(id);
if (string.IsNullOrEmpty(token))
{
return Task.FromResult(new SomeObject()
{
IsAuthorized = false
});
}
else
{
return repository.GetSomeObjectByTokenAsync(token).ContinueWith(t =>
{
t.Result.IsAuthorized = true;
return t.Result;
});
}
}
Above method can be awaited and I think it closely resembles to what the Task-based Asynchronous Pattern suggests doing? (The other patterns I know of are the APM and EAP patterns.)
Now, what about the following code:
public async Task<SomeObject> GetSomeObjectByToken(int id)
{
string token = repository.GetTokenById(id);
if (string.IsNullOrEmpty(token))
{
return new SomeObject()
{
IsAuthorized = false
};
}
else
{
SomeObject result = await repository.GetSomeObjectByTokenAsync(token);
result.IsAuthorized = true;
return result;
}
}
The key differences here are that the method is async and it utilizes the await keywords - so what does this change in contrast to the previously written method? I know it can too - be awaited. Any method returning Task can for that matter, unless I'm mistaken.
I'm aware of the state machine created with those switch statements whenever a method is labeled as async, and I'm aware that await itself uses no thread - it doesn't block at all, the thread simply goes to do other things, until it's called back to continue execution of the above code.
But what's the underlying difference between the two methods, when we invoke them using the await keyword? Is there any difference at all, and if there is - which is preferred?
EDIT: I feel like the first code snippet is preferred, because we effectively elide the async/await keywords, without any repercussions - we return a task that will continue its execution synchronously, or an already completed task on the hot path (which can be cached).
The async/await mechanism makes the compiler transform your code into a state machine. Your code will run synchronously until the first await that hits an awaitable that has not completed, if any.
In the Microsoft C# compiler, this state machine is a value type, which means it will have a very small cost when all awaits get completed awaitables, as it won't allocate an object, and therefore, it won't generate garbage. When any awaitable is not completed, this value type is inevitably boxed. 1
Note that this doesn't avoid allocation of Tasks if that's the type of awaitables used in the await expressions.
With ContinueWith, you only avoid allocations (other than Task) if your continuation doesn't have a closure and if you either don't use a state object or you reuse a state object as much as possible (e.g. from a pool).
Also, the continuation is called when the task is completed, creating a stack frame, it doesn't get inlined. The framework tries to avoid stack overflows, but there may be a case where it won't avoid one, such as when big arrays are stack allocated.
The way it tries to avoid this is by checking how much stack is left and, if by some internal measure the stack is considered full, it schedules the continuation to run in the task scheduler. It tries to avoid fatal stack overflow exceptions at the cost of performance.
Here is a subtle difference between async/await and ContinueWith:
async/await will schedule continuations in SynchronizationContext.Current if any, otherwise in TaskScheduler.Current 2
ContinueWith will schedule continuations in the provided task scheduler, or in TaskScheduler.Current in the overloads without the task scheduler parameter
To simulate async/await's default behavior:
.ContinueWith(continuationAction,
SynchronizationContext.Current != null ?
TaskScheduler.FromCurrentSynchronizationContext() :
TaskScheduler.Current)
To simulate async/await's behavior with Task's .ConfigureAwait(false):
.ContinueWith(continuationAction,
TaskScheduler.Default)
Things start to get complicated with loops and exception handling. Besides keeping your code readable, async/await works with any awaitable.
Your case is best handled with a mixed approach: a synchronous method that calls an asynchronous method when needed. An example of your code with this approach:
public Task<SomeObject> GetSomeObjectByTokenAsync(int id)
{
string token = repository.GetTokenById(id);
if (string.IsNullOrEmpty(token))
{
return Task.FromResult(new SomeObject()
{
IsAuthorized = false
});
}
else
{
return InternalGetSomeObjectByTokenAsync(repository, token);
}
}
internal async Task<SomeObject> InternalGetSomeObjectByToken(Repository repository, string token)
{
SomeObject result = await repository.GetSomeObjectByTokenAsync(token);
result.IsAuthorized = true;
return result;
}
In my experience, I've found very few places in application code where adding such complexity actually pays off the time to develop, review and test such approaches, whereas in library code any method can be a bottleneck.
The only case where I tend elide tasks is when a Task or Task<T> returning method simply returns the result of another asynchronous method, without itself having performed any I/O or any post-processing.
YMMV.
When building for Release, the compiler generates structs.
When building for Debug, the compiler generates classes to allow edit-and-continue on async code.
Unless you use ConfigureAwait(false) or await on some awaitable that uses custom scheduling.
By using ContinueWith you are using the tools that where available before the introduction of the async/await functionality with C# 5 back at 2012. As a tool it is verbose, not easily composable, it has a potentially confusing default scheduler¹, and requires extra work for unwrapping AggregateExceptions and Task<Task<TResult>> return values (you get these when you pass asynchronous delegates as arguments). It offers few advantages in return. You may consider using it when you want to attach multiple continuations to the same Task, or in some rare cases where you can't use async/await for some reason (like when you are in a method with out parameters).
¹ If the scheduler argument is not provided, it defaults to TaskScheduler.Current, and not to TaskScheduler.Default as one might expect. This means that by default when the ContinueWith is attached, the ambient TaskScheduler.Current is captured, and used for scheduling the continuation. This is somewhat similar with how the await captures the ambient SynchronizationContext.Current, and schedules the continuation after the await on this context. To prevent this behavior of await you can use the ConfigureAwait(false), and to prevent this behavior of ContinueWith you can use the TaskContinuationOptions.ExecuteSynchronously flag in combination with passing the TaskScheduler.Default. Most experts suggest to specify always the scheduler argument every time you use the ContinueWith, and not rely on the ambient TaskScheduler.Current. Specialized TaskSchedulers are generally doing more funky stuff than specialized SynchronizationContexts. For example the ambient scheduler could be a limited concurrency scheduler, in which case the continuation might be put in a queue of unrelated long-running tasks, and executed a long time after the associated task has completed.
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.
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.)
This question already has answers here:
Any difference between "await Task.Run(); return;" and "return Task.Run()"? [duplicate]
(4 answers)
Closed 6 years ago.
Method 1:
private static async Task FirstDelayAsync()
{
await Task.Delay(1000);
}
Method 2:
private static Task SecondDelayAsync()
{
return Task.Delay(1000);
}
Please help me to find the difference:
await FirstDelayAsync();
await SecondDelayAsync();
Thanks.
The two are very similar. When it encounters an async method, the C# compiler will generate a state machine, such that the returned Task represents the completion of your method. Since the only thing that your method does is await another asynchronous operation, then this will be functionally almost equivalent to returning the Task from the inner asynchronous operation directly.
There is, however, a subtle difference concerning how exceptions from the synchronous part will be thrown. Any logic performed within async methods, including the synchronous part at the beginning of the method (before the first await statement), will be compiled as part of the asynchronous operation. This means that precondition exceptions will no longer be delivered synchronously, but asynchronously through the returned Task:
private static async Task FirstDelayAsync()
{
if (StateNotValid)
throw new NotSupportedException();
await Task.Delay(1000);
}
private static Task SecondDelayAsync()
{
if (StateNotValid)
throw new NotSupportedException();
return Task.Delay(1000);
}
Testing out the above code:
var t1 = FirstDelayAsync();
await t1; // exception thrown here
var t2 = SecondDelayAsync(); // exception thrown here
await t2;
This won't make a difference if you await your asynchronous operation on the same line that you call it. However, it would make a difference if you delay the awaiting; for example, if you launch several asynchronous operations concurrently and then await them together using Task.WhenAll:
var tasks = Enumerable
.Range(0, 10)
.Select(i => ProcessAsync(i))
.ToArray();
await Task.WhenAll(tasks);
In the above snippet, synchronous exceptions thrown from the ProcessAsync calls would prevent the subsequent asynchronous operations from even being launched, since the exception immediately stops the enumeration. This is usually preferable for failed preconditions that should stop the entire process.
Update: Another important different is that using await without ConfigureAwait(false) will make your code more liable to deadlock. See this answer.
Functionally, there is no difference between the two methods. They work the same.
async and await allow you to create complex asynchronous methods by allowing you to write code that looks like synchronous code but is actually asynchronous.
For simple cases like the one you have, the second approach is preferred since the first approach creates a state machine to handle the asynchronous logic. Such state machine is definitely needed in case of complex asynchronous methods, but is not needed for this simple case.
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.