Unused async/await pairs are removed to optimize and reduce compiled code#104
Unused async/await pairs are removed to optimize and reduce compiled code#104R0ma-D wants to merge 1 commit intoprogaudi:masterfrom R0ma-D:master
Conversation
|
Yes, but your change has some implications: public class A
{
private IDisposable d;
public Task F()
{
return d.DoAsync();
}
public void Dispose()
{
d.Dispose();
}
}If you call F, then in some other thread user call Dispose, the caller of F will receive very strange behaviour. If we set async/await in F, there will be either ODI, or he will get result. Also, I would like to see some benchmarks with and without async. Without them we will not accept this PR. |
|
I've attach "benchmark" class. With async keyword it takes 493 ms to create 10000 tasks, and only 4 ms without it. `class Program |
|
We are not just "creating" tasks in air. We are making network calls with latencies large enough to be considered. Also, I suggest to use BenchmarkDotNet I'll try to write a benchmark next week to test it. How should we alleviate problem with disposable objects? |
|
I do not quite understand the problem. What will be unexpected for the end user? May be CancellationToken as input parameter decide problem? Or could you provide an example of d.DoAsync() method? |
|
So, I finally did the tests. Results shows no improvement on excluding async-await. Sorry, I had a lot of work to do on main job. Code for non-async-await is at #106. I look forward where can we improve code more, but I think network exchange will remove any difference here. Async-await BenchmarkDotNet=v0.10.7, OS=Windows 10 Redstone 2 (10.0.15063)
Processor=Intel Core i5-4590 CPU 3.30GHz (Haswell), ProcessorCount=4
Frequency=3215209 Hz, Resolution=311.0218 ns, Timer=TSC
dotnet cli version=1.0.0
[Host] : .NET Core 4.6.25211.01, 64bit RyuJIT
Core : .NET Core 4.6.25211.01, 64bit RyuJIT
Job=Core Runtime=Core
Without async-await BenchmarkDotNet=v0.10.7, OS=Windows 10 Redstone 2 (10.0.15063)
Processor=Intel Core i5-4590 CPU 3.30GHz (Haswell), ProcessorCount=4
Frequency=3215209 Hz, Resolution=311.0218 ns, Timer=TSC
dotnet cli version=1.0.0
[Host] : .NET Core 4.6.25211.01, 64bit RyuJIT
Core : .NET Core 4.6.25211.01, 64bit RyuJIT
Job=Core Runtime=Core
|
|
It looks like you are right and all possible performance improvement spends by network communication. Thank you for your efforts. |
|
Since we have improvements on our network stack in 0.8.0, I'll redo the tests this week, I hope. |
|
Test for one call. 2200 RPS. BenchmarkDotNet=v0.10.9, OS=Windows 10.0.16299
Processor=Intel Core i5-4590 CPU 3.30GHz (Haswell), ProcessorCount=4
Frequency=3215210 Hz, Resolution=311.0217 ns, Timer=TSC
.NET Core SDK=2.0.0
[Host] : .NET Core 2.0.0 (Framework 4.6.00001.0), 64bit RyuJIT
netcore1.1 : .NET Core 1.1.2 (Framework 4.6.25211.01), 64bit RyuJIT
netcore2.0 : .NET Core 2.0.0 (Framework 4.6.00001.0), 64bit RyuJIT
Jit=RyuJit Platform=X64 Runtime=Core
Toolchain=CoreCsProj
Batch=100. 61k RPS. BenchmarkDotNet=v0.10.9, OS=Windows 10.0.16299
Processor=Intel Core i5-4590 CPU 3.30GHz (Haswell), ProcessorCount=4
Frequency=3215210 Hz, Resolution=311.0217 ns, Timer=TSC
.NET Core SDK=2.0.0
[Host] : .NET Core 2.0.0 (Framework 4.6.00001.0), 64bit RyuJIT
netcore1.1 : .NET Core 1.1.2 (Framework 4.6.25211.01), 64bit RyuJIT
netcore2.0 : .NET Core 2.0.0 (Framework 4.6.00001.0), 64bit RyuJIT
Jit=RyuJit Platform=X64 Runtime=Core
Toolchain=CoreCsProj
Batch=1000, 90815 RPS BenchmarkDotNet=v0.10.9, OS=Windows 10.0.16299
Processor=Intel Core i5-4590 CPU 3.30GHz (Haswell), ProcessorCount=4
Frequency=3215210 Hz, Resolution=311.0217 ns, Timer=TSC
.NET Core SDK=2.0.0
[Host] : .NET Core 2.0.0 (Framework 4.6.00001.0), 64bit RyuJIT
netcore1.1 : .NET Core 1.1.2 (Framework 4.6.25211.01), 64bit RyuJIT
netcore2.0 : .NET Core 2.0.0 (Framework 4.6.00001.0), 64bit RyuJIT
Jit=RyuJit Platform=X64 Runtime=Core
Toolchain=CoreCsProj
|
BenchmarkDotNet=v0.10.9, OS=Windows 10.0.16299
Processor=Intel Core i5-4590 CPU 3.30GHz (Haswell), ProcessorCount=4
Frequency=3215210 Hz, Resolution=311.0217 ns, Timer=TSC
.NET Core SDK=2.0.0
[Host] : .NET Core 2.0.0 (Framework 4.6.00001.0), 64bit RyuJIT
netcore1.1 : .NET Core 1.1.2 (Framework 4.6.25211.01), 64bit RyuJIT
netcore2.0 : .NET Core 2.0.0 (Framework 4.6.00001.0), 64bit RyuJIT
Jit=RyuJit Platform=X64 Runtime=Core
Toolchain=CoreCsProj
Benchmarks with issues: |

If some method can be written without await, then it should be written it without await, and remove the async keyword from the method. A non-async method returning Task is more efficient than an async method returning a value/void. Check here:
http://blog.stephencleary.com/2012/02/async-and-await.html
Simple async method:
public async Task UndirectTaskMethod()
{
return await Task.FromResult(0);
}
generate complex method based on state machine like this:
[DebuggerStepThrough, AsyncStateMachine(typeof(AsyncClassObject.d__1))]
public Task UndirectTaskMethod()
{
AsyncClassObject.d__1 d__ = new AsyncClassObject.d__1();
d__.<>4__this = this;
d__.<>t__builder = AsyncTaskMethodBuilder.Create();
d__.<>1__state = -1;
AsyncTaskMethodBuilder <>t__builder = d__.<>t__builder;
<>t__builder.Start<AsyncClassObject.d__1>(ref d__);
return d__.<>t__builder.Task;
}