I'm doing a benchmark on Task<T> and ValueTask<T>. Source code below:
#LINQPad optimize+ // Enable compiler optimizations
void Main()
{
Util.AutoScrollResults = true;
BenchmarkRunner.Run<TaskAndValueTaskComparsion>();
}
[ShortRunJob]
public class TaskAndValueTaskComparsion
{
[Benchmark]
public ValueTask<int> RunValueTaskWithNew()
{
return new ValueTask<int>(1);
}
[Benchmark]
public Task<int> RunTaskFromResult()
{
return Task.FromResult(1);
}
}
For the result, the Task<T> is way faster than ValueTask<T>. But why? I really expected the ValueTask<T> would cause less allocation when returning task objects.
Thanks for all the commenters. Let's summarize all these valuable info.
There is a TaskCache.cs in the .NET runtime that create cacheable Task for various primitive type's value such as true(bool), false(bool), -1 ~ 9(int). The Task.FromResult leverage these cached Task for it.
So, the benchmark result is incorrect because the Task.FromResult is always return cached version of Task object, and the new ValueTask<int>(1) always returns a new value.
For more information, please read Understanding the Whys, Whats, and Whens of ValueTask.
If you can read Chinese, I also wrote a post yesterday. See here.
Related
Is there any scenario where writing method like this:
public async Task<SomeResult> DoSomethingAsync()
{
// Some synchronous code might or might not be here... //
return await DoAnotherThingAsync();
}
instead of this:
public Task<SomeResult> DoSomethingAsync()
{
// Some synchronous code might or might not be here... //
return DoAnotherThingAsync();
}
would make sense?
Why use return await construct when you can directly return Task<T> from the inner DoAnotherThingAsync() invocation?
I see code with return await in so many places, I think I might have missed something. But as far as I understand, not using async/await keywords in this case and directly returning the Task would be functionally equivalent. Why add additional overhead of additional await layer?
There is one sneaky case when return in normal method and return await in async method behave differently: when combined with using (or, more generally, any return await in a try block).
Consider these two versions of a method:
Task<SomeResult> DoSomethingAsync()
{
using (var foo = new Foo())
{
return foo.DoAnotherThingAsync();
}
}
async Task<SomeResult> DoSomethingAsync()
{
using (var foo = new Foo())
{
return await foo.DoAnotherThingAsync();
}
}
The first method will Dispose() the Foo object as soon as the DoAnotherThingAsync() method returns, which is likely long before it actually completes. This means the first version is probably buggy (because Foo is disposed too soon), while the second version will work fine.
If you don't need async (i.e., you can return the Task directly), then don't use async.
There are some situations where return await is useful, like if you have two asynchronous operations to do:
var intermediate = await FirstAsync();
return await SecondAwait(intermediate);
For more on async performance, see Stephen Toub's MSDN article and video on the topic.
Update: I've written a blog post that goes into much more detail.
The only reason you'd want to do it is if there is some other await in the earlier code, or if you're in some way manipulating the result before returning it. Another way in which that might be happening is through a try/catch that changes how exceptions are handled. If you aren't doing any of that then you're right, there's no reason to add the overhead of making the method async.
Another case you may need to await the result is this one:
async Task<IFoo> GetIFooAsync()
{
return await GetFooAsync();
}
async Task<Foo> GetFooAsync()
{
var foo = await CreateFooAsync();
await foo.InitializeAsync();
return foo;
}
In this case, GetIFooAsync() must await the result of GetFooAsync because the type of T is different between the two methods and Task<Foo> is not directly assignable to Task<IFoo>. But if you await the result, it just becomes Foo which is directly assignable to IFoo. Then the async method just repackages the result inside Task<IFoo> and away you go.
If you won't use return await you could ruin your stack trace while debugging or when it's printed in the logs on exceptions.
When you return the task, the method fulfilled its purpose and it's out of the call stack.
When you use return await you're leaving it in the call stack.
For example:
Call stack when using await:
A awaiting the task from B => B awaiting the task from C
Call stack when not using await:
A awaiting the task from C, which B has returned.
Making the otherwise simple "thunk" method async creates an async state machine in memory whereas the non-async one doesn't. While that can often point folks at using the non-async version because it's more efficient (which is true) it also means that in the event of a hang, you have no evidence that that method is involved in the "return/continuation stack" which sometimes makes it more difficult to understand the hang.
So yes, when perf isn't critical (and it usually isn't) I'll throw async on all these thunk methods so that I have the async state machine to help me diagnose hangs later, and also to help ensure that if those thunk methods ever evolve over time, they'll be sure to return faulted tasks instead of throw.
This also confuses me and I feel that the previous answers overlooked your actual question:
Why use return await construct when you can directly return Task from the inner DoAnotherThingAsync() invocation?
Well sometimes you actually want a Task<SomeType>, but most time you actually want an instance of SomeType, that is, the result from the task.
From your code:
async Task<SomeResult> DoSomethingAsync()
{
using (var foo = new Foo())
{
return await foo.DoAnotherThingAsync();
}
}
A person unfamiliar with the syntax (me, for example) might think that this method should return a Task<SomeResult>, but since it is marked with async, it means that its actual return type is SomeResult.
If you just use return foo.DoAnotherThingAsync(), you'd be returning a Task, which wouldn't compile. The correct way is to return the result of the task, so the return await.
Another reason for why you may want to return await: The await syntax lets you avoid hitting a mismatch between Task<T> and ValueTask<T> types. For example, the code below works even though SubTask method returns Task<T> but its caller returns ValueTask<T>.
async Task<T> SubTask()
{
...
}
async ValueTask<T> DoSomething()
{
await UnimportantTask();
return await SubTask();
}
If you skip await on the DoSomething() line, you'll get a compiler error CS0029:
Cannot implicitly convert type 'System.Threading.Tasks.Task<BlaBla>' to 'System.Threading.Tasks.ValueTask<BlaBla>'.
You'll get CS0030 too, if you try to explicitly typecast it.
This is .NET Framework, by the way. I can totally foresee a comment saying "that's fixed in .NET hypothetical_version", I haven't tested it. :)
Another problem with non-await method is sometimes you cannot implicitly cast the return type, especially with Task<IEnumerable<T>>:
async Task<List<string>> GetListAsync(string foo) => new();
// This method works
async Task<IEnumerable<string>> GetMyList() => await GetListAsync("myFoo");
// This won't work
Task<IEnumerable<string>> GetMyListNoAsync() => GetListAsync("myFoo");
The error:
Cannot implicitly convert type 'System.Threading.Tasks.Task<System.Collections.Generic.List>' to 'System.Threading.Tasks.Task<System.Collections.Generic.IEnumerable>'
The question asked here is the same as the one here and is aimed to create a definitive solution to it.
The most accurate answer is by Stephen Toub himself in this issue that is exactly about this question. The "recommendended code" is the following one:
public static ValueTask AsValueTask<T>(this ValueTask<T> valueTask)
{
if (valueTask.IsCompletedSuccessfully)
{
valueTask.GetResult();
return default;
}
return new ValueTask(valueTask.AsTask());
}
This answer is not up-to-date - a ValueTask doesn't expose a GetResult() (only a Result property) - and THE question is:
Do we need to "pull" the Result out of the ValueTask (to "release" the IValueTaskSource that may operate under this ValueTask)?
If yes:
is it the .GetAwaiter() call that is missing above?
OR is a fake call to the property is guaranteed to work var fake = valueTask.Result;? Always? (I'm afraid of dead code elimination.)
If not, is a straight implementation like the following one enough (and optimal)?
public static ValueTask AsNonGenericValueTask<T>( in this ValueTask<T> valueTask )
{
return valueTask.IsCompletedSuccessfully ? default : new ValueTask( valueTask.AsTask() );
}
What's missing in that code is .GetAwaiter():
public static ValueTask AsValueTask<T>(this ValueTask<T> valueTask)
{
if (valueTask.IsCompletedSuccessfully)
{
valueTask.GetAwaiter().GetResult();
return default;
}
return new ValueTask(valueTask.AsTask());
}
You're partially right in that you don't care about the result. But you might care about a thrown exception or cancellation that you'll miss if you don't query the result.
Or you can write it like this:
public static async ValueTask AsValueTask<T>(this ValueTask<T> valueTask)
=> await valueTask;
You can use either:
valueTask.GetAwaiter().GetResult();
...or:
_ = valueTask.Result;
Both of those delegate to the underlying IValueTaskSource<T>.GetResult method, assuming that the ValueTask<T> is backed by a IValueTaskSource<T>. Using the shorter (second) approach should be slightly more efficient, since it involves one less method invocation.
You could also omit getting the result entirely. There is no requirement that a ValueTask<T> must be awaited at least once, or that its result must be retrieved at least once. It is entirely valid to be handed a ValueTask<T> and then forget about it. The documented restriction is:
A ValueTask<TResult> instance may only be awaited once, [...]
It's a "may only", not a "must".
It is still a good idea to get the result though. By retrieving the result you are signaling that the ValueTask<TResult> has been consumed, and so the underlying IValueTaskSource<T> can be reused. Reusing IValueTaskSource<T> instances makes ValueTask<T>-based implementations more efficient, because they allocate memory less frequently. To get an idea, take a look at the internal System.Threading.Channels.AsyncOperation<TResult> class. This class implements the IValueTaskSource<TResult> interface. Here is how the GetResult is implemented:
/// <summary>Gets the result of the operation.</summary>
/// <param name="token">The token that must match <see cref="_currentId"/>.</param>
public TResult GetResult(short token)
{
if (_currentId != token)
{
ThrowIncorrectCurrentIdException();
}
if (!IsCompleted)
{
ThrowIncompleteOperationException();
}
ExceptionDispatchInfo? error = _error;
TResult? result = _result;
_currentId++;
if (_pooled)
{
Volatile.Write(ref _continuation, s_availableSentinel); // only after fetching all needed data
}
error?.Throw();
return result!;
}
Setting the private field Action<object> _continuation to the static readonly value s_availableSentinel allows the AsyncOperation<TResult> to be reused by a subsequent asynchronous operation (like the ChannelReader.ReadAsync for example). Otherwise the next asynchronous operation will allocate a new AsyncOperation<TResult> instance.
I have an ASP.NET app running on .NET 4.6.1.
I can't use .Sum() on my awaited GetInts() result. The compiler thinks that GetInts() is a task. SumIntsOneLinerBroker() doesn't compile.
public Task<List<int>> GetInts() {
var list = new List<int> { 4, 5 };
return Task.FromResult(list);
}
public async Task<int> SumInts() {
var ints = await GetInts();
return ints.Sum();
}
public async Task<int> SumIntsOneLinerBroker() {
return await GetInts().Sum();
}
public async Task<int> SumIntsOneLinerWorking() {
return (await GetInts()).Sum();
}
There are a few ways of handling this. The most common is probably the parentheses that you show in your code and confirmed by Marc.
An alternative is .ContinueWith which lets you pass the result of the first operation to the second. Here's a Microsoft Example. Keep in mind, when you utilize ContinueWith, exceptions will get wrapped in an AggregateException, which can alter your exception handling.
Confirmed by Marc, the parentheses enclosing method as seen in the second image is the proper approach. Nothing to see here.
This question already has answers here:
How does Task<int> become an int?
(2 answers)
Closed 7 years ago.
I've got code very similar to this (I've simplified the code a bit to demonstrate the essence of the behavior I'm trying to figure out).
public async System.Threading.Tasks.Task<bool> IsNumberOdd(int numToTest)
{
if (numToTest % 2 == 0)
{
return false;
}
else
{
return true;
}
}
If I leave off the async keyword, I get a complaint about not being able to cast a bool to a Task<bool>. I'm assuming there's some syntactic sugar involved here. Looking at the IL (I'm not super familiar with IL) it seems as if the async keyword is causing the task to be run and then the return value is the result of the task. Am I understanding this correctly?
By the way, if this is a dupe or if there's some blog posting that discusses this, feel free to point me to it and close this up. I'm not trying to pad my rep; I'm trying to understand what's going on with this code.
EDIT:
For all those who were asking "why is this method async?"--because I was trying to build a small and simple code example to demonstrate the question. I should have also added an example of the calling code but I was trying to keep the code as small and simple as I could.
I'm assuming there's some syntactic sugar involved here
Not exactly "syntactic sugar". The compiler is generating a state-machine as the method was marked as async. That is why you can return a Task<bool> without explicitly creating a Task for the return value.
If I leave off the async keyword, I get a complaint about not being
able to cast a bool to a Task<bool>.
The async modifier is what triggers the compiler to create the state machine. If you remove it, you'll need to create the Task yourself. If for any reason you want to create a Task<T> but you're actually running synchronously, Task.FromResult is your friend.
I see no reason why this method is marked async.
it seems as if the async keyword is causing the task to be run and then the return value is the result of the task
Correct.
There is nothing in this method that would benefit from it being async. However:
If I leave off the async keyword, I get a complaint about not being able to cast a bool to a Task<bool>
Would be happening in the caller. Without seeing that code one can only comment generally that you can either:
Change the caller to not assume it is getting a waitable return.
Change the function to return bool, but on the caller use Task.FromResult(IsNumberOdd(value)).
It's not about the async. Its about the Task.
your returning a bool and the return value of your function is Task
public Task<bool> DoSomething()
{
return false;
}
will also not compile.
if your not doing any thing asynchronous you shouldn't return a Task.
If you need to run something asynchronously , here are a few options which i hope will make the usage of async/await clearer.
public class Sample
{
public async void RunSample()
{
// return a task. later obtain a result if some fashion
Task<bool> task = DoSomethingAsync();
bool res1 = task.Result;
// await a task which is created for you by re-wrapping the result.
bool res2 = await AwaitSomethingAsync();
// await a task which is created for you by rewrapping the result due to await.
bool res3 = await DoSomethingAsync2();
// await a task.
bool res4 = await DoSomethingAsync();
}
public async Task<bool> DoSomethingAsync2()
{
return false;
}
public Task<bool> DoSomethingAsync()
{
return Task<bool>.Run(() => { return false; });
}
public async Task<bool> AwaitSomethingAsync()
{
bool res = await Task<bool>.Run(() => { return false; });
return res; // re-wraps it in a Task
}
}
The following code compiles and runs well. But where is the return statement for the Consumer() and Producer() methods?
class Program
{
static BufferBlock<Int32> m_buffer = new BufferBlock<int>(
new DataflowBlockOptions { BoundedCapacity = 10 });
public static async Task Producer() <----- How is a Task object returned?
{
while (true)
{
await m_buffer.SendAsync<Int32>(DateTime.Now.Second);
Thread.Sleep(1000);
}
}
public static async Task Consumer() <----- How is a Task object returned?
{
while (true)
{
Int32 n = await m_buffer.ReceiveAsync<Int32>();
Console.WriteLine(n);
}
}
static void Main(string[] args)
{
Task.WaitAll(Consumer(), Producer());
}
}
While your question states the obvious - the code compiles - and the other answers try to explain-by-example, I think the answer is best described in the following two articles:
"Above-the-surface" answer - full article is here: http://msdn.microsoft.com/en-us/magazine/hh456401.aspx
[...] C# and Visual Basic [...] giving enough hints to the compilers
to build the necessary mechanisms for you behind the scenes. The
solution has two parts: one in the type system, and one in the
language.
The CLR 4 release defined the type Task [...] to represent the
concept of “some work that’s going to produce a result of type T in
the future.” The concept of “work that will complete in the future but
returns no result” is represented by the non-generic Task type.
Precisely how the result of type T is going to be produced in the
future is an implementation detail of a particular task; [...]
The language half of the solution is the new await keyword. A regular
method call means “remember what you’re doing, run this method until
it’s completely finished, and then pick up where you left off, now
knowing the result of the method.” An await expression, in contrast,
means “evaluate this expression to obtain an object representing work
that will in the future produce a result. Sign up the remainder of the
current method as the callback associated with the continuation of
that task. Once the task is produced and the callback is signed up,
immediately return control to my caller.”
2.The under-the-hood explanation is found here: http://msdn.microsoft.com/en-us/magazine/hh456403.aspx
[...] Visual Basic and C# [...] let you express discontinuous
sequential code. [...] When the Visual Basic or C# compiler gets hold
of an asynchronous method, it mangles it quite a bit during
compilation: the discontinuity of the method is not directly supported
by the underlying runtime and must be emulated by the compiler. So
instead of you having to pull the method apart into bits, the compiler
does it for you. [...]
The compiler turns your asynchronous method into a statemachine. The
state machine keeps track of where you are in the execution and what
your local state is. [...]
Asynchronous methods produce Tasks. More specifically, an asynchronous
method returns an instance of one of the types Task or Task from
System.Threading.Tasks, and that instance is automatically generated.
It doesn’t have to be (and can’t be) supplied by the user code. [...]
From the compiler’s point of view, producing Tasks is the easy part.
It relies on a framework-supplied notion of a Task builder, found in
System.Runtime.CompilerServices [...] The builder lets the compiler
obtain a Task, and then lets it complete the Task with a result or an
Exception. [...] Task builders are special helper types meant only for
compiler consumption. [...]
[...] build up a state machine around the production and consumption
of the Tasks. Essentially, all the user logic from the original method
is put into the resumption delegate, but the declarations of locals
are lifted out so they can survive multiple invocations. Furthermore,
a state variable is introduced to track how far things have gotten,
and the user logic in the resumption delegate is wrapped in a big
switch that looks at the state and jumps to a corresponding label. So
whenever resumption is called, it will jump right back to where it
left off the last time.
when the method has no return statement its return type is Task. Have a look at the MSDN page of Async Await
Async methods have three possible return types: Task<TResult>, Task, void
if you need a Task you must specify the return statement. Taken from the MSDN page:
// TASK<T> EXAMPLE
async Task<int> TaskOfT_MethodAsync()
{
// The body of the method is expected to contain an awaited asynchronous
// call.
// Task.FromResult is a placeholder for actual work that returns a string.
var today = await Task.FromResult<string>(DateTime.Now.DayOfWeek.ToString());
// The method then can process the result in some way.
int leisureHours;
if (today.First() == 'S')
leisureHours = 16;
else
leisureHours = 5;
// Because the return statement specifies an operand of type int, the
// method must have a return type of Task<int>.
return leisureHours;
}
async keyword kind of tells compiler that the method body should be used as a Task body. In simple way we can say that these are equivalents to your examples:
public static Task Producer() <----- How is a Task object returned?
{
return Task.Run(() =>
{
while (true)
{
m_buffer.SendAsync<Int32>(DateTime.Now.Second).Wait();
Thread.Sleep(1000);
}
});
}
public static Task Consumer() <----- How is a Task object returned?
{
return Task.Run(() =>
{
while (true)
{
Int32 n = m_buffer.ReceiveAsync<Int32>().Wait();
Console.WriteLine(n);
}
});
}
Of course the compiled result of your methods will be completely different from my examples, because compiler smart enough and it can generate code in such way, so some of the lines in your method will be invoked on the context (thread), which calls the method and some of them on the background context. And this is actually why Thread.Sleep(1000); is not recommended in the body of async methods, because this code can be invoked on the thread, which calls this method. Task has equivalent which can replace Thread.Sleep(1000); the equivalent await Task.Delay(1000), which will be invoked on background thread. As you can see await keyword guaranties you that this call will be invoked on the background context and will not block the caller context.
Let's take a look on one more example:
async Task Test1()
{
int a = 0; // Will be called on the called thread.
int b = await this.GetValueAsync(); // Will be called on background thread
int c = GetC(); // Method execution will come back to the called thread again on this line.
int d = await this.GetValueAsync(); // Going again to background thread
}
So we can say that this will be generated code:
Task Test1()
{
int a = 0; // Will be called on the called thread.
vat syncContext = Task.GetCurrentSynchronizationContext(); // This will help us go back to called thread
return Task.Run(() =>
{
// We already on background task, so we safe here to wait tasks
var bTask = this.GetValueAsync();
bTask.Wait();
int b = bTask.Result;
// syncContext helps us to invoke something on main thread
// because 'int c = 1;' probably was expected to be called on
// the caller thread
var cTask = Task.Run(() => return GetC(), syncContext);
cTask.Wait();
int c = cTask.Result;
// This one was with 'await' - calling without syncContext,
// not on the thread, which calls our method.
var dTask = this.GetValueAsync();
dTask.Wait();
int d = dTask.Result;
});
}
Again, this is not the same code which you will get from compiler, but it should just give you some idea how this works. If you really want to take a look on what will be in the produced library, use for example IlSpy to take a look on generated code.
Also I really recommend to read this article Best Practices in Asynchronous Programming
That's exactly what the async keyword means. It takes a method and (usually) converts it to a Task returning method. If the normal method would have the return type of void, the async method will have Task. If the return type would be some other T, the new return type will be Task<T>.
For example, to download an process some data synchronously, you could write something like:
Foo GetFoo()
{
string s = DownloadFoo();
Foo foo = ParseFoo(s);
return foo;
}
The asynchronous version would then look like this:
Task<Foo> GetFoo()
{
string s = await DownloadFoo();
Foo foo = ParseFoo(s);
return foo;
}
Notice that the return type changed from Foo to Task<Foo>, but you're still returning just Foo. And similarly with void-returning methods: since they don't have to contain a return statement, async Task (without any <T>) methods also don't.
The Task object is constructed by the compiler-generated code, so you don't have to do that.