簡體   English   中英

從數組中刪除,鏡像(奇怪)行為

[英]Deleting from array, mirrored (strange) behavior

標題可能看起來有點奇怪,因為我不知道如何用一句話來描述這個。

對於課程算法,我們必須微觀優化一些東西,一個是找出如何從數組中刪除。 賦值是從數組中刪除某些內容並重新對齊內容以便沒有間隙,我認為它與std :: vector :: erase在c ++中的工作方式非常相似。

因為我喜歡低級理解所有內容的想法,所以我更進一步嘗試了解決方案。 這提出了一些奇怪的結果。

首先,這是我使用的一些代碼:

class Test {

    Stopwatch sw;
    Obj[] objs;

    public Test() {
        this.sw = new Stopwatch();
        this.objs = new Obj[1000000];

        // Fill objs
        for (int i = 0; i < objs.Length; i++) {
            objs[i] = new Obj(i);
        }
    }

    public void test() {

        // Time deletion
        sw.Restart();
        deleteValue(400000, objs);
        sw.Stop();

        // Show timings
        Console.WriteLine(sw.Elapsed);
    }

    // Delete function
    // value is the to-search-for item in the list of objects
    private static void deleteValue(int value, Obj[] list) {

        for (int i = 0; i < list.Length; i++) {

            if (list[i].Value == value) {
                for (int j = i; j < list.Length - 1; j++) {
                    list[j] = list[j + 1];

                    //if (list[j + 1] == null) {
                    //    break;
                    //}
                }
                list[list.Length - 1] = null;
                break;
            }
        }
    }
}

我只是創建這個類並調用test()方法。 我這循環做了25次。

我的發現:

  • 第一輪它需要比其他24更長的時間,我認為這是因為緩存,但我不確定。
  • 當我使用列表開頭的值時,它必須在內存中移動的項目比在最后使用值時更多,但它似乎仍然需要更少的時間。
  • 基准時間差別很大。
  • 當我啟用已注釋的if時,即使我搜索的值幾乎位於列表的末尾,性能也會上升(10-20%)(這意味着if會在沒有實際用處的情況下發生很多次)。

我不知道為什么會發生這些事情,是否有人可以解釋(部分)這些事情? 也許如果有人看到這是誰的專業人士,我在哪里可以找到更多信息以最有效的方式做到這一點?

測試后編輯:

我做了一些測試,發現了一些有趣的結果。 我在一個大小為一百萬個項目的數組上運行測試,其中包含一百萬個對象。 我運行了25次,並以毫秒為單位報告累計時間。 我做了10次並將其平均值作為最終值。

當我使用上面描述的函數運行測試時,得到的分數為:362,1

當我用dbc的答案運行它時得到的分數為:846,4

所以我的速度更快,但后來我開始嘗試半空的空陣列,事情開始變得怪異。 為了擺脫不可避免的nullPointerExceptions,我添加了一個額外的檢查if(認為它會破壞更多的性能),如下所示:

if (fromItem != null && fromItem.Value != value)
    list[to++] = fromItem;

這似乎不僅有效,而且可以大大提高性能! 現在我的得分為:247,9

奇怪的是,分數看起來很低,但有時是秒殺,這是我從平均值中得到的集合:94,26,966,36,632,95,47,35,109,439

所以額外的評估似乎可以提高我的表現,盡管做了額外的檢查。 這怎么可能?

您正在使用Stopwatch為您的方法Stopwatch 這將計算方法調用期間所用的總時鍾時間,其中可能包括.Net最初JIT方法所需的時間 ,垃圾收集中斷或其他進程的系統負載導致的速度減慢。 由於緩存未命中,來自這些源的噪聲可能會主導噪聲。

這個答案提供了一些建議,說明如何最大限度地減少垃圾收集或其他過程中的一些噪音。 要消除JIT噪聲,您應該在沒有計時的情況下調用方法一次 - 或者在結果表的單獨列中顯示第一次調用所花費的時間,因為它會如此不同。 您還可以考慮使用適當的分析器 ,它將准確報告您的代碼使用的時間,而不包括來自其他線程或進程的“噪音”。

最后,我會注意到你從數組中刪除匹配項並向下移動其他所有內容的算法使用嵌套循環,這不是必需的,並且會在匹配索引兩次后訪問數組中的項。 標准算法如下所示:

    public static void RemoveFromArray(this Obj[] array, int value)
    {
        int to = 0;
        for (int from = 0; from < array.Length; from++)
        {
            var fromItem = array[from];
            if (fromItem.Value != value)
                array[to++] = fromItem;
        }
        for (; to < array.Length; to++)
        {
            array[to] = default(Obj);
        }
    }

但是,您可以通過將Array.RemoveAt()與您的版本一起使用,而不是使用標准算法,因為(我相信)內部它會在非托管代碼中執行刪除。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM