NET-933 Modify S1155: Add benchmarks (#4592)

This commit is contained in:
Sebastien Marichal 2025-01-08 10:23:49 +01:00 committed by GitHub
parent a2aa406613
commit 43247cd487
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -5,6 +5,14 @@ When you call `Any()`, it clearly communicates the code's intention, which is to
* if the collection is an `EntityFramework` or other ORM query, calling `Count()` will cause executing a potentially massive SQL query and could put a large overhead on the application database. Calling `Any()` will also connect to the database, but will generate much more efficient SQL.
* if the collection is part of a LINQ query that contains `Select()` statements that create objects, a large amount of memory could be unnecessarily allocated. Calling `Any()` will be much more efficient because it will execute fewer iterations of the enumerable.
== How to fix it
Prefer using `Any()` to test for emptiness over `Count()`.
=== Code examples
==== Noncompliant code example
[source,csharp,diff-id=1,diff-type=noncompliant]
----
private static bool HasContent(IEnumerable<string> strings)
@ -23,7 +31,7 @@ private static bool IsEmpty(IEnumerable<string> strings)
}
----
Prefer using `Any()` to test for emptiness over `Count()`.
==== Compliant solution
[source,csharp,diff-id=1,diff-type=compliant]
----
@ -43,6 +51,59 @@ private static bool IsEmpty(IEnumerable<string> strings)
}
----
== Resources
=== Benchmarks
[options="header"]
|===
| Method | Runtime | Mean | Standard Deviation
| Count | .NET 9.0 | 2,841.003 ns | 266.0238 ns
| Any | .NET 9.0 | 1.749 ns | 0.1242 ns
| Count | .NET Framework 4.8.1 | 71,125.275 ns | 731.0382 ns
| Any | .NET Framework 4.8.1 | 31.774 ns | 0.3196 ns
|===
==== Glossary
* https://en.wikipedia.org/wiki/Arithmetic_mean[Mean]
* https://en.wikipedia.org/wiki/Standard_deviation[Standard Deviation]
The results were generated by running the following snippet with https://github.com/dotnet/BenchmarkDotNet[BenchmarkDotNet]:
[source,csharp]
----
private IEnumerable<int> collection;
public const int N = 10_000;
[GlobalSetup]
public void GlobalSetup()
{
collection = Enumerable.Range(0, N).Select(x => N - x);
}
[Benchmark(Baseline = true)]
public bool Count() =>
collection.Count() > 0;
[Benchmark]
public bool Any() =>
collection.Any();
----
Hardware Configuration:
[source]
----
BenchmarkDotNet v0.14.0, Windows 10 (10.0.19045.5247/22H2/2022Update)
12th Gen Intel Core i7-12800H, 1 CPU, 20 logical and 14 physical cores
[Host] : .NET Framework 4.8.1 (4.8.9282.0), X64 RyuJIT VectorSize=256
.NET 9.0 : .NET 9.0.0 (9.0.24.52809), X64 RyuJIT AVX2
.NET Framework 4.8.1 : .NET Framework 4.8.1 (4.8.9282.0), X64 RyuJIT VectorSize=256
----
ifdef::env-github,rspecator-view[]
'''
@ -101,7 +162,7 @@ Added the `Count() == 0` to the description and extended the code samples
\[~ann.campbell.2] You are right, I removed the comparison to `0`.
=== on 27 May 2015, 14:04:31 Ann Campbell wrote:
Thanks [~tamas.vajk]. I've merged the code blocks into one block each for Compliant and Noncompliant
Thanks [~tamas.vajk]. I've merged the code blocks into one block each for Compliant and Noncompliant
=== on 1 Jun 2015, 14:30:42 Ann Campbell wrote:
I've updated the examples with `List<string>`. Please double-check me.