Array bounds check efficiency in .net 4 and above

后端 未结 4 983
离开以前
离开以前 2020-12-05 06:19

I\'m interested in how efficient low-level algorithms can be in .net. I would like to enable us to choose to write more of our code in C# rather than C++ in the future, but

4条回答
  •  死守一世寂寞
    2020-12-05 06:49

    First of all, I would like to thank everyone who spoken out in this post, from original OP to the guys who provided extremely detailed and insightful explanations. I really, really enjoyed reading the existing answers. Since there is already plentiful of theory of how and why the loops work in the way they do, I would like to offer some empirical (by some definition authoritative) measurements:

    Conclusions:

    • Foreach loop is faster than For loop.
    • Local variable is faster than the array .Length property.
    • GC-pinning using unsafe fixed is not faster than normal For loop.

    Benchmarking code:

    using System;
    using System.Diagnostics;
    using System.Runtime;
    
    namespace demo
    {
        class MainClass
        {
            static bool ByForArrayLength (byte[] data)
            {
                for (int i = 0; i < data.Length; i++)
                    if (data [i] != 0)
                        return false;
                return true;
            }
    
            static bool ByForLocalLength (byte[] data)
            {
                int len = data.Length;
                for (int i = 0; i < len; i++)
                    if (data [i] != 0)
                        return false;
                return true;
            }
    
            static unsafe bool ByForUnsafe (byte[] data)
            {
                fixed (byte* datap = data)
                {
                    int len = data.Length;
                    for (int i = 0; i < len; i++)
                        if (datap [i] != 0)
                            return false;
                    return true;
                }
            }
    
            static bool ByForeach (byte[] data)
            {
                foreach (byte b in data)
                    if (b != 0)
                        return false;
                return true;
            }
    
            static void Measure (Action work, string description)
            {
                GCSettings.LatencyMode = GCLatencyMode.LowLatency;
                var watch = Stopwatch.StartNew ();
                work.Invoke ();
                Console.WriteLine ("{0,-40}: {1} ms", description, watch.Elapsed.TotalMilliseconds);
            }
    
            public static void Main (string[] args)
            {
                byte[] data = new byte[256 * 1024 * 1024];
                Measure (() => ByForArrayLength (data), "For with .Length property");
                Measure (() => ByForLocalLength (data), "For with local variable");
                Measure (() => ByForUnsafe (data), "For with local variable and GC-pinning");
                Measure (() => ByForeach (data), "Foreach loop");
            }
        }
    }
    

    Results: (uses Mono runtime)

    $ mcs Program.cs -optimize -unsafe
    For with .Length property               : 440,9208 ms
    For with local variable                 : 333,2252 ms
    For with local variable and GC-pinning  : 330,2205 ms
    Foreach loop                            : 280,5205 ms
    

提交回复
热议问题