Here is a benchmark for methods return task, but run synchronizely under the hood.
class MainClass
{
public static async Task<int> UsingAsyncModifier()
{
return 10;
}
public static Task<int> UsingTaskCompletionSource()
{
TaskCompletionSource<int> tcs = new TaskCompletionSource<int>();
tcs.SetResult(10);
return tcs.Task;
}
public static Task<int> UsingTaskFromResult()
{
return Task.FromResult(10);
}
public static void Main(string[] args)
{
DateTime t = DateTime.Now;
const int repeat = 10000; // Results volatile while repeat grows.
Console.WriteLine("Repeat {0} times.", repeat);
int j = 0;
for (int i = 0; i < repeat; i++)
{
j += UsingAsyncModifier().Result;
}
Console.WriteLine("UsingAsyncModifier: {0}", DateTime.Now - t);
t = DateTime.Now;
for (int i = 0; i < repeat; i++)
{
j += UsingTaskCompletionSource().Result;
}
Console.WriteLine("UsingTaskCompletionSource: {0}", DateTime.Now - t);
t = DateTime.Now;
for (int i = 0; i < repeat; i++)
{
j += UsingTaskFromResult().Result;
}
Console.WriteLine("UsingTaskFromResult: {0}", DateTime.Now - t);
}
}
Output (repeat 10,000/100,000/1000,000 times):
Repeat 10000 times.
UsingAsyncModifier: 00:00:00.1043980
UsingTaskCompletionSource: 00:00:00.0095270
UsingTaskFromResult: 00:00:00.0089460
Repeat 10,000 times, UsingTaskFromResult 10x faster than UsingAsyncModifier.
Repeat 100000 times.
UsingAsyncModifier: 00:00:00.1676000
UsingTaskCompletionSource: 00:00:00.0872020
UsingTaskFromResult: 00:00:00.0870180
Repeat 100,000 times, UsingTaskFromResult 2x faster than UsingAsyncModifier.
Repeat 1000000 times.
UsingAsyncModifier: 00:00:00.8458490
UsingTaskCompletionSource: 00:00:00.8870980
UsingTaskFromResult: 00:00:00.9027320
Repeat 1,000,000 times, UsingAsyncModifier slightly faster than UsingTaskFromResult.
What I think was, the async
modifier just created an completed Task, something like Task.FromResult()
does. But the benchmark does not prove my idea.
Why?
While I see the similar results using DateTime
, the use of Stopwatch
for time measuring shows that iterations using UsingAsyncModifier()
take 2 times more time duration (than using UsingTaskCompletionSource()
or UsingTaskFromResult()
, both showing equal appr. duration) even with 1 000 000 iterations
Here is output:
Repeat 1000000 times.
UsingAsyncModifier: 5458
UsingTaskCompletionSource: 2838
UsingTaskFromResult: 2556
with your code using Stopwatch
class Program
{
public static async Task<int> UsingAsyncModifier()
{
return 10;
}
public static Task<int> UsingTaskCompletionSource()
{
TaskCompletionSource<int> tcs = new TaskCompletionSource<int>();
tcs.SetResult(10);
return tcs.Task;
}
public static Task<int> UsingTaskFromResult()
{
return TaskEx.FromResult(10);
}
static void Main(string[] args)
{
//DateTime t = DateTime.Now;
Stopwatch timer = new Stopwatch();
const int repeat = 1000*1000; // Results volatile while repeat grows.
Console.WriteLine("Repeat {0} times.", repeat);
int j = 0;
//DateTime t = DateTime.Now;
timer.Start();
for (int i = 0; i < repeat; i++)
{
j += UsingAsyncModifier().Result;
}
timer.Stop();
Console.WriteLine("UsingAsyncModifier: {0}"
, timer.ElapsedMilliseconds);
//t = DateTime.Now;
timer.Reset();
j = 0;
timer.Start();
for (int i = 0; i < repeat; i++)
{
j += UsingTaskCompletionSource().Result;
}
timer.Stop();
Console.WriteLine("UsingTaskCompletionSource: {0}"
, timer.ElapsedMilliseconds);
//t = DateTime.Now;
timer.Reset();
j = 0;
timer.Start();
for (int i = 0; i < repeat; i++)
{
j += UsingTaskFromResult().Result;
}
timer.Stop();
Console.WriteLine("UsingTaskFromResult: {0}"
, timer.ElapsedMilliseconds);
Console.ReadLine();
}
}
Stephen Toub in his "Async Performance: Understanding the Costs of Async and Await" explains:
When working with synchronous code, methods with empty bodies are practically free. This is not the case for asynchronous methods
Read it for much more details
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With