• Frugal Cafe
  • Posts
  • FC42: Linq.Enumerable.Any could be slower in .Net Core

FC42: Linq.Enumerable.Any could be slower in .Net Core

Linq is still Not Quick in .Net Core

In FC07 Examine simplest Linq.Enumerable method: Any (beehiiv.com), we discussed how is Linq.Enumerable.Any implemented in .Net Framework, why it’s slow, and how to replace it.

Here is the implementation in .Net Framework:

It’s implemented purely on enumeration. An enumerator always needs to be allocated.

I checked its implementation in the latest version of .Net Core:

The new implementation tries to get the Count property and check if it’s not zero. This will avoid enumerator allocation problem.

But getting the Count property is not cheap. There are three interface casting operations here: for ICollection, IIListProvider, and ICollection. Interface casting is not cheap.

If Count property is available, its implementation normally is quite efficient. But this is not always the case. For example, ConcurrentDictionary Count property implementation is expensive, because it needs to take all locks. CoucnrrentBag has similar implementation.

Some containers have Count property, but they do not implement those three interfaces. For example, some collection just implements IReadOnlyList interface, or IReadOnlyCollection interface.

In conclusion, Linq.Enumerable.Any implementation in .Net Core could be faster, could be slower than its old implementation in .Net Framework.

What should developers do then, you may ask? Frugal Cafe suggestion is do not use Linq.Enumerable in hot code paths, replace them all; do not write new code using Linq.Enumerable. In .Net Core, Linq is still Not Quick.

Simple test, calling string.Any():

String does not implement any of those three interfaces, so the new implementation needs to pay for three casting operations and enumerator allocation.

Windbg wt trace (trimmed):

279 instructions. The .Net Framework implementation we tested before (FC07 Examine simplest Linq.Enumerable method: Any (beehiiv.com)), it’s 143 instructions.

We have proved that the new implementation for Linq.Enumerable.Any could be slower in .Net Core (7.0 tested).