What is the overhead of a “synchronized” asynchronous access method?

Here is the benchmark for the method return task, but synchronize 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); } } 

Exit (repeat 10,000 / 100,000 / 1,000,000 times):

 Repeat 10000 times. UsingAsyncModifier: 00:00:00.1043980 UsingTaskCompletionSource: 00:00:00.0095270 UsingTaskFromResult: 00:00:00.0089460 

Repeat 10,000 times using TaskFromResult 10 times 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 using UseTaskFromResult 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 is a little faster than UseTaskFromResult.

I think the async modifier has just created a completed task, something like Task.FromResult() . But this checkpoint does not prove my idea. Why?

+4
source share
1 answer

While I see similar results using DateTime , using Stopwatch to measure time shows that iterations using UsingAsyncModifier() take 2 times longer (than using UsingTaskCompletionSource() or UsingTaskFromResult() duration) even with 1,000,000 iterations

It displays here:

 Repeat 1000000 times. UsingAsyncModifier: 5458 UsingTaskCompletionSource: 2838 UsingTaskFromResult: 2556 

using 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 Tube in his Async Performance: Understanding the Costs of Async and Await explains:

When working with synchronous code, methods with empty bodies are almost free. This does not apply to asynchronous methods.

Read it for more details.

+2
source

Source: https://habr.com/ru/post/1481870/


All Articles