-
Notifications
You must be signed in to change notification settings - Fork 17
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Unused async/await pairs are removed to optimize and reduce compiled code #104
base: master
Are you sure you want to change the base?
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;
}