C#/.NET Method Call Performance - Facts
Ivan G
Posted on May 28, 2021
Wondering what's the difference in performance for different method types in C#? Is performance the same for static, dynamic, virtual methods? What about asynchronous calls?
Here are the raw performance measurements:
Method | Mean | Error | StdDev | Median | Min | Max | Gen 0 | Gen 1 | Gen 2 | Allocated |
---|---|---|---|---|---|---|---|---|---|---|
Static | 0.0093 ns | 0.2315 ns | 0.0127 ns | 0.0042 ns | 0.0000 ns | 0.0238 ns | - | - | - | - |
StaticAsync | 19.6042 ns | 0.8500 ns | 0.0466 ns | 19.6287 ns | 19.5505 ns | 19.6334 ns | 0.0172 | - | - | 72 B |
Dynamic | 0.0601 ns | 1.2112 ns | 0.0664 ns | 0.0488 ns | 0.0000 ns | 0.1313 ns | - | - | - | - |
DynamicAsync | 20.8642 ns | 6.1827 ns | 0.3389 ns | 20.8004 ns | 20.5618 ns | 21.2305 ns | 0.0172 | - | - | 72 B |
Virtual | 0.6320 ns | 1.0647 ns | 0.0584 ns | 0.6246 ns | 0.5776 ns | 0.6937 ns | - | - | - | - |
VirtualAsync | 21.3301 ns | 6.2675 ns | 0.3435 ns | 21.4575 ns | 20.9410 ns | 21.5916 ns | 0.0172 | - | - | 72 B |
That's eye opening to be honest.
Summary
- Static methods are 6 times faster than normal instance methods.
- Static methods are 68 times faster than virtual methods.
- Virtual methods are 10.5 times slower than instance methods. Makes you think to carefully choose which methods should be virtual.
- Async calls allocate 72 bytes of memory, regardless of method signature. Normal methods have no impact on memory allocations.
- Regardless of method signature, all of the async method calls are really slow.
- The slowest method signature (virtual async) is 2293 (two thousand two hundred ninety three) times slower than the fastest method signature (static method).
Appendix. Performance Testing Source Code.
#LINQPad optimize+
void Main()
{
Util.AutoScrollResults = true;
BenchmarkRunner.Run<MethodCalls>();
}
[ShortRunJob]
[MinColumn, MaxColumn, MeanColumn, MedianColumn]
[MemoryDiagnoser]
[MarkdownExporter]
public class MethodCalls
{
private MethodsContainer _c = new MethodsContainer();
[Benchmark]
public int Static()
{
return MethodsContainer.StaticMethod(1);
}
[Benchmark]
public async Task<int> StaticAsync()
{
return await MethodsContainer.StaticAsyncMethod(1);
}
[Benchmark]
public int Dynamic()
{
return _c.DynamicMethod(1);
}
[Benchmark]
public async Task<int> DynamicAsync()
{
return await _c.DynamicAsyncMethod(1);
}
[Benchmark]
public int Virtual()
{
return _c.VirtualMethod(1);
}
[Benchmark]
public async Task<int> VirtualAsync()
{
return await _c.VirtualAsyncMethod(1);
}
}
public class MethodsContainer
{
public static int StaticMethod(int arg) { return arg * 2; }
public static Task<int> StaticAsyncMethod(int arg) { return Task.FromResult<int>(arg * 2); }
public int DynamicMethod(int arg) { return arg * 2; }
public Task<int> DynamicAsyncMethod(int arg) { return Task.FromResult<int>(arg * 2); }
public virtual int VirtualMethod(int arg) { return arg * 2; }
public virtual Task<int> VirtualAsyncMethod(int arg) { return Task.FromResult<int>(arg * 2); }
}
P.S. Originally posted on my blog - you might want to subscribe for future updates.
💖 💪 🙅 🚩
Ivan G
Posted on May 28, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
webdev Understanding Garbage Collection in .NET: How to Optimize Memory Management
September 29, 2024