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

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).

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..

Async Task gives warning, (without) Async Task gives error

This is probably a more of a finesse question but I have the following method inside a ViewComponent class
public async Task<IViewComponentResult> InvokeAsync()
{
return View();
}
but the name InvokeAsync is underlined and gives the following warning
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
but if I try removing the async from the method then return View() is underlined with red and outputs the following error
'Microsoft.AspNetCore.Mvc.ViewComponents.ViewViewComponentResult' to
'System.Threading.Tasks.Task' MVCStateManagement
So my question is what approach should I take? Let the async there indiferently of the warning, or is there a workaround / fix for this warning? Does it have that much of an impact on my project?
Thanks!
It's unclear why the method was defined as an async method that returns a Task<IViewComponentResult> in the first place.
Since the method seems to be truly synchronous and simply returns a view, you should probably define it like this:
public IViewComponentResult Invoke()
{
return View();
}
A synchronous method doesn't magically become asynchronous just because you add the async keyword to it.
If you are implementing an interface and cannot change the signature of the method, you could use the Task.FromResult method to return an already completed task (you should still remove the async keyword):
public Task<IViewComponentResult> InvokeAsync()
{
return Task.FromResult<IViewComponentResult>(View());
}
The method runs on a Task of ViewcomponentResult.
You can call it without async by using this:
public Task<IViewComponentResult> InvokeAsync()
{
return Task.FromResult<IViewComponentResult>(View());
}
Your warning will no longer show and your code will run.
You could also leave it. Either will have no impact on the performance of your project.
You have to remove the async flag and the Task<>. Just return a IViewComponentResult.
You will tipically return a object wrapped into Task<> when you do async work. If you don´t it does not make any sense.
From MSDN:
The Task class represents a single operation that returns a
value and that usually executes asynchronously. Task objects
are one of the central components of the task-based asynchronous
pattern first introduced in the .NET Framework 4. Because the work
performed by a Task object typically executes asynchronously
on a thread pool thread rather than synchronously on the main
application thread, you can use the Status property, as well as the
IsCanceled, IsCompleted, and IsFaulted properties, to determine the
state of a task. Most commonly, a lambda expression is used to specify
the work that the task is to perform.
https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task-1?view=netframework-4.7.2
EDIT:
You can also try returning:
return Task.FromResult<IViewComponentResult>(View());

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.)

Using Async and Await in 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.

Asynchronous method that does nothing

I have an interface IAnimation which exposes a method BeginAsync(). That method should start the animation and return when it is completed.
What I would like to do is implement a null animation class NoAnimation that just returns when it executes BeginAsync().
Is this the right implementation?
public async Task BeginAsync()
{
await Task.Run(() => { });
}
I suspect that there is a more elegant approach than this. I also considered
creating an empty method. But that gives me a warning which I don't like either.
Just use Task.CompletedTask to return a completed task:
public Task BeginAsync()
{
return Task.CompletedTask;
}
If you have a Task<TResult> use Task.FromResult<TResult> to return a completed task with a result:
public Task<bool> BeginAsync()
{
return Task.FromResult(true);
}
Your current implementation is very inefficient, as it builds the state machine, and also uses a ThreadPool thread to run the empty task.
I appreciate this doesn't exactly answer the original question (or at least not in a way that isn't already in another answer). What it does it provide additional context for #ReedCopsey's answer, for those (including me! and others, based on the comments on that answer) who initially might find it hard to understand what is going on here.
It's very easy to fall into the trap of thinking that async must be part of the signature of any asynchronous method. It looks as if it must be; it (misleadingly!) reads as if it's whole purpose is to mark a method as asynchronous.
But it's not, Task or Task<T> are required, but not async. This is shown in #ReedCopsey's answer and in the following correct example (slightly adapted from this useful SO answer):
public Task<int> MethodTaskAsync(int arg0, int arg1)
{
Task<int> task = new Task<int>(() => Method(arg0, arg1));
task.Start(); // Hot task (started task) should always be returned.
return task;
}
That's why interface method signatures don't need, and can't have, the async keyword: an 'asynchronous' method per se, without regard to how it might be implemented, is just a method that returns a started (and, possibly, already finished) Task or Task<T>.
If async doesn't mark a method as asynchronous, what does it do? It's a way to write asynchronous methods more simply: once you have applied it to a method, you can use the await keyword to tell the compiler to correctly handle subsidiary asynchronous calls for you very simply (without it, you could try to handle subsidiary Tasks manually, using lots more code like that in the code block above, but to do so would be very complex and error prone).
So if you just want to return a do-nothing, already-completed task from an 'asynchronous' (i.e. Task-returning) method, you can and should do so synchronously(!), as in #ReedCopsey 's answers, using Task.CompletedTask or Task.FromResult(...).

Categories

Resources