c#中Debug和Release的區別實驗

環境:

  • window 10
  • vs 2019 16.4.5
  • .netcore 3.1.1

參照:
項目發佈Debug和Release版的區別
享受release版本發佈的好處的同時也應該警惕release可能給你引入一些莫名其妙的大bug

一、Releas版本相比Debug版本的性能提升很大

Debug模式在編譯時不對源代碼進行優化,而Release模式進行了大膽的優化,使得程序在代碼大小和運行速度上都有顯著提高。
下面通過一個對10000條數據進行冒泡排序的例子來比較它們二者的性能差距:

class Program
{
    public static void Main(string[] args)
    {
        //準備測試數據
        var len = 10000;
        var datas = new int[len];
        for (int i = 0; i < len; i++)
        {
            datas[i] = new Random().Next(1, 100000);
        }
        //冒泡排序5次
        for (int i = 0; i < 5; i++)
        {
            var arr = new int[datas.Length];
            datas.CopyTo(arr, 0);
            Stopwatch watch = new Stopwatch();
            watch.Start();
            Order(arr);
            watch.Stop();
            Console.WriteLine(watch.Elapsed);
        }
        Console.WriteLine("ok");
        Console.Read();
    }

    public static int[] Order(int[] datas)
    {
        for (int i = 0; i < datas.Length; i++)
        {
            for (int j = i + 1; j < datas.Length; j++)
            {
                if (datas[i] < datas[j])
                {
                    int t = datas[i];
                    datas[i] = datas[j];
                    datas[j] = t;
                }
            }
        }
        return datas;
    }
}

Debug模式的輸出:
在這裏插入圖片描述
Release模式的輸出:
在這裏插入圖片描述
從上滿可以看到,將近三倍的性能差距!!!

二、Releas版本可能會出現莫名的bug

雖然通過上面的對比可以看到Releas版本有着較大的性能優勢,但同時它也可能帶來了莫名的bug。上面說到,編譯器對代碼進行了大膽的優化,比如說將一些值直接讀取到cpu高速緩存中,這在多線程的操作環境中就可能帶來問題,下面看一個例子:

class Program
 {
     static int isStop = 0;
     public static void Main()
     {
         var t = new Thread(() =>
         {
             var isSuccess = true;
             while (isStop == 0)
             {
                 isSuccess = !isSuccess;
             }
         });
         t.Start();
         Thread.Sleep(1000);
         isStop = 1;
         t.Join();
         Console.WriteLine("ok");
         Console.ReadLine();
     }
 }

Debug版本的輸出:
在這裏插入圖片描述
Release版本的輸出:
在這裏插入圖片描述
可以看到,Release版本沒有輸出,說明它死循環了沒有讀取到isStop 的改變值,這其實就是Release版本的優化導致的。Releas版本把isStop緩存到了CPU的告訴緩存中,導致主線程修改了isStop的值卻不能反饋到新線程上去。

那麼有沒有解決辦法呢?

  • 辦法1:不要在多線程中這麼操作變量。
  • 辦法2:不要使用Releas版本
  • 辦法3:使用MemoryBarrier/VolatileRead
  • 辦法4:使用volatile 關鍵字

其實,真正解決問題的就是辦法3和辦法4,那麼我們看看這兩個是什麼東西:

  • VolatileRead:忽略CPU的高速緩存,獲取最新的數據,這句話執行後就會將isStop刷新,從下面的註釋中也可以看得出來
    在這裏插入圖片描述
    上面的代碼使用Release編譯後發現是正常的了。
  • MemoryBarrier:參照:MemoryBarrier方法
    在這裏插入圖片描述
    使用上面的代碼處理後,Release再編譯也正常了。
  • volatile關鍵字
    這個關鍵字要用在類的字段上,如下所示:
    在這裏插入圖片描述
    這樣使用Release編譯後也正常了。

三、Release版本的調試問題

在調試中去掉"僅我的代碼“即可!
在這裏插入圖片描述
這樣,無論你是F5或者是附加到進程都是可以調試的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章