I understand unsafe code is more appropriate to access things like the Windows API and do unsafe type castings than to write more performant code, but I would like to ask you if you have ever noticed any significant performance improvement in real-world applications by using it when compared to safe c# code.
Some Performance Measurements
The performance benefits are not as great as you might think.
I did some performance measurements of normal managed array access versus unsafe pointers in C#.
Results from a build run outside of Visual Studio 2010, .NET 4, using an Any CPU | Release build on the following PC specification: x64-based PC, 1 quad-core processor. Intel64 Family 6 Model 23 Stepping 10 GenuineIntel ~2833 Mhz.
Linear array access 00:00:07.1053664 for Normal 00:00:07.1197401 for Unsafe *(p + i) Linear array access - with pointer increment 00:00:07.1174493 for Normal 00:00:10.0015947 for Unsafe (*p++) Random array access 00:00:42.5559436 for Normal 00:00:40.5632554 for Unsafe Random array access using Parallel.For(), with 4 processors 00:00:10.6896303 for Normal 00:00:10.1858376 for Unsafe
Note that the unsafe *(p++)
idiom actually ran slower. My guess this broke a compiler optimization that was combining the loop variable and the (compiler generated) pointer access in the safe version.
Source code available on github.
unsafe
keyword, and using ptr++
. That is valuable info; I appreciate that. What's missing is any insight into when unsafe
might be much faster - or conversely, showing that unsafe
isn't faster, in more substantial calculations. However, this is a useful starting point; thanks. –
Verbiage As was stated in other posts, you can use unsafe code in very specialised contexts to get a significant performance inprovement. One of those scenarios is iterating over arrays of value types. Using unsafe pointer arithmetic is much faster than using the usual pattern of for-loop/indexer..
struct Foo
{
int a = 1;
int b = 2;
int c = 0;
}
Foo[] fooArray = new Foo[100000];
fixed (Foo* foo = fooArray) // foo now points to the first element in the array...
{
var remaining = fooArray.length;
while (remaining-- > 0)
{
foo->c = foo->a + foo->b;
foo++; // foo now points to the next element in the array...
}
}
The main benefit here is that we've cut out array index checking entirely..
While very performant, this kind of code is hard to handle, can be quite dangerous (unsafe), and breaks some fundamental guidelines (mutable struct). But there are certainly scenarios where this is appropriate...
A good example is image manipulations. Modifying the Pixels by using a pointer to their bytes (which requires unsafe code) is quite a bit faster.
Example: http://www.gutgames.com/post/Using-Unsafe-Code-for-Faster-Image-Manipulation.aspx
That being said, for most scenarios, the difference wouldn't be as noticeable. So before you use unsafe code, profile your application to see where the performance bottlenecks are and test whether unsafe code is really the solution to make it faster.
byte[]
you can even avoid that and just use Marshal
functions. –
Dartmoor GetPixel
and SetPixel
is really slow but using int[]
is more or less as fast as using pointers without the drawbacks. –
Hinterland Marshal
yet though. –
Hinterland Well, I would suggest to read this blog-post: MSDN blogs: Array Bounds Check Elimination in the CLR
This clarifies how bounds-checks are done in C#. Moreover, Thomas Bratts tests seem to me useless (looking at the code) since the JIT removes in his 'save' loops the bound-checks anyway.
I am using unsafe code for video manipulation code. In such code you want it to run as fast as possible without internal checks on values etc. Without unsafe attributes my could would not be able to keep up with the video stream at 30fps or 60 fps. (depending on used camera).
But because of speed its widely used by people who code graphics.
To all that are looking at these answers I would like to point out that even though the answers are excellent, a lot has changed sins the answers have been posted.
Please note that .net has changed quite a bit and one now also has the possibility to access new data types like vectors, Span, ReadOnlySpan as well as hardware specific libraries and classes like those found in System.Runtime.Intrinsics in core 3.0
Have a look at this blog post to see how hardware optimized loops could be used and this blog how to fallback to safe methods if optimal hardware is not available.
© 2022 - 2024 — McMap. All rights reserved.
unsafe
... I'm not sure the reasoning follows... Besides: have you measured to see if you are doing something useful here? – Helainehelaliunsafe
, make sure you know how to efficiently use C#. Avoid excessive creation of temp objects. When to use an array of structs, and gotchas to watch out for.Buffer.BlockCopy
. The conditions under which JIT optimizes out array bounds-checking. (I am not an expert, just saying what comes to mind.) Google C# high performance and C# performance tips. – Verbiage