Hacker News new | ask | show | jobs
by starburst 957 days ago
LINQ is pretty much frowned upon when programming games in C#, also when doing performance comparison you want to get as close as possible to the actual code without the extra overhead.

I would very much verify anything and not take it at face value when a C# performance post use LINQ.

3 comments

LINQ codepaths are only getting faster. A literal army of engineers is focused on this stuff full time.

https://devblogs.microsoft.com/dotnet/performance_improvemen...

> dotnet/runtime#64470 is the result of analyzing various real-world code bases for use of Enumerable.Min and Enumerable.Max, and seeing that it’s very common to use these with arrays, often ones that are quite large. This PR updates the Min<T>(IEnumerable<T>) and Max<T>(IEnumerable<T>) overloads when the input is an int[] or long[] to vectorize the processing, using Vector<T>. The net effect of this is significantly faster execution time for larger arrays, but still improved performance even for short arrays (because the implementation is now able to access the array directly rather than going through the enumerable, leading to less allocation and interface dispatch and more applicable optimizations like inlining).

What are the chances that you'd have patience to write a competitive bug-free SIMD implementation?

Games in C# might be written in Unity, and a lot of those improvements wouldn't apply there. So in that context this might be accurate because it's an entirely different runtime.
The relationship between LINQ and performance is not trivial, it pretty much depends on what you do (more complex LINQ chain -> worse overhead).

It does have base cost (allocating iterator object(s)), but it's less than what you think, I have seen enough game code that does intermediate list allocations when it doesn't need to, which are far costlier than LINQ.

In addition, the benchmarks that do other positive work alongside the benchmarked aspect can sometimes be more illustrative and overall better because it is much more important how a particular approach works together with surrounding code, matching more closely real world scenarios.

And last but not least - in this case using structs yields additional advantage with LINQ since monomorphization of methods where generic arguments are structs has additional codegen quality benefits.

It is certainly possible to write slow code without LINQ, all I'm saying is that I wouldn't blindly trust a blog post that talk about performance and use LINQ.
The article contents suggest deep understanding of the topic.

This type of thinking ("LINQ bad" or "SOLID good") is one reason among many why bad patterns proliferate through the projects e.g. "hey you should rewrite this code with SOLID principles in mind" (without accounting for the context) or "This code calculates the sum using LINQ, you should rewrite it" (LINQ's Sum implementation uses SIMD and is hard to beat).

The article is fine, I was referencing the original article the article is referencing.
fwiw, it's possible to use LINQ in games no problem if you provide your own implementation(s) of the core LINQ methods you care about. I'm using LINQ and async/await in my game with no problems (~900fps, one short gen0/gen1 GC every 70 seconds or so) since I did the work to write zero-allocation versions of the basic operators like Select and Where. The design of LINQ is such that the C# compiler will use whatever implementation of the operator(s) is available when it converts your SQL-y queries into actual code.

I suspect the BCL doesn't include zero-allocation query operators because they generalize poorly, but I'm not sure. Zero-allocation query operators end up looking like 'ZeroAllocSelect<TEnumerable, TSource, TResult> Select (this TEnumerable seq, Func<TSource, TResult> func) where TEnumerable : IEnumerable<TSource>' which is obviously not trivial for the JIT to compile (or trivial to write)

The closures it creates for your queries are kind of a pain though. It's possible that will have improved in NET8 or NET9 because the allocation rules for delegates were recently revised to allow more optimizations, but I don't know if that was fixed.

I actually love the syntax if only it didn't alloc, is your implementation open source?