技術(shù)頻道導(dǎo)航
HTML/CSS
.NET技術(shù)
IIS技術(shù)
PHP技術(shù)
Js/JQuery
Photoshop
Fireworks
服務(wù)器技術(shù)
操作系統(tǒng)
網(wǎng)站運(yùn)營(yíng)

贊助商

分類目錄

贊助商

最新文章

搜索

測(cè)試一下C# ArryList與List的性能差異,結(jié)果有點(diǎn)意外

作者:admin    時(shí)間:2023-5-13 7:32:26    瀏覽:

前面介紹過(guò)官方建議使用List而不是ArryList,雖然理論上那樣說(shuō),但沒(méi)有經(jīng)過(guò)實(shí)驗(yàn)測(cè)試比較,不太能令人信服。出于好奇心,便測(cè)試了一下C# ArryListList的性能差異,結(jié)果有點(diǎn)意外。

前幾天,一位朋友問(wèn)了我一個(gè)簡(jiǎn)單的問(wèn)題,我看了看他的代碼,他沒(méi)有使用 List<T>,而是使用了類型“ArrayList”。老實(shí)說(shuō),我甚至不記得上次使用 ArrayList 是什么時(shí)候了。我認(rèn)為當(dāng)我開(kāi)始在 .NET 2 中編程時(shí),我可能無(wú)法足夠快地理解泛型,而 ArrayList 似乎是一個(gè)替代品。

有什么不同?

兩者之間的主要區(qū)別在于 ArrayList 僅包含“對(duì)象”類型,這意味著理論上它是一盒你想要的任何東西,例如這段代碼編譯得很好:

ArrayList arrayList = new ArrayList();
arrayList.Add(123);
arrayList.Add("abc");
arrayList.Add(new object());

然后在代碼上從數(shù)組列表中抓取內(nèi)容以“檢查”它的類型是否正確。在實(shí)踐中,你不會(huì)隨意地將各種類型放入數(shù)組列表中,因此實(shí)際上它更像是編譯時(shí)的“松散”。如果我們將它與 List 進(jìn)行比較:

List<int> list = new List<int>();
list.Add(123);
list.Add("abc"); //編譯時(shí)錯(cuò)誤

它知道我們只想存儲(chǔ)整數(shù)并且試圖將任何其他東西塞進(jìn)去是行不通的。

但是這個(gè)呢?

List<object> list = new List<object>();
list.Add(123);
list.Add("abc");

這行得通嗎?對(duì)象列表幾乎與 ArrayList 相同。

如果我們查看 ArrayList 實(shí)現(xiàn)的接口: 

public class ArrayList : ICollection, IEnumerable, IList, ICloneable

List 基本上與一些通用接口相同,但是當(dāng)你檢查這些時(shí),除了使用類型的“Add”等通用方法之外,它們不會(huì)添加任何東西:

public class List<T> : ICollection<T>, IEnumerable<T>, IEnumerable, IList<T>, IReadOnlyCollection<T>, IReadOnlyList<T>, ICollection, IList

但事情發(fā)生變化的地方是使用 LINQ。幾乎所有方法(我說(shuō)幾乎,但我認(rèn)為它是全部)都建立在 IEnumerable<T> 而不是 IEnumerable 之上。例如,LINQ 中的 Where 子句如下所示:

public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)

這意味著你不能在 ArrayList 上使用 LINQ。在某些用例中,這沒(méi)什么大不了的,但你確實(shí)可以免費(fèi)獲得 LINQ……所以選擇一個(gè)不支持它的類型真的是無(wú)緣無(wú)故地搬起石頭砸自己的腳。

性能影響

在某些情況下,在選擇 ArrayList 而不是 List<T> 時(shí)會(huì)對(duì)性能產(chǎn)生很大影響。這歸結(jié)為“裝箱”和“拆箱”的行為。簡(jiǎn)單來(lái)說(shuō),裝箱就是采用一個(gè)值類型(比如整數(shù))并將其包裝在一個(gè)對(duì)象中,并將其存儲(chǔ)在堆上而不是堆棧上。

但這對(duì) ListArrayList 有何影響?當(dāng)我們?cè)?ArrayList 中存儲(chǔ)一個(gè)項(xiàng)目時(shí),它必須是對(duì)象類型(或類型),如果我們?cè)?ArrayList 中存儲(chǔ)一個(gè)值類型,那么在存儲(chǔ)它之前,它必須先“裝箱”對(duì)象并將其包裝起來(lái),List<int> 沒(méi)有相同的裝箱成本(盡管 List<object> 會(huì))。

為了對(duì)此進(jìn)行測(cè)試,我使用BenchmarkDotNet創(chuàng)建了一個(gè)基準(zhǔn)。BenchmarkDotNet可幫助你將方法轉(zhuǎn)化為基準(zhǔn)、跟蹤其性能并共享可重現(xiàn)的測(cè)量實(shí)驗(yàn)。參閱文章:

public class ArrayListVsListWrite
{
    int itemCount = 10000000;
    public ArrayList arrayList;
    public List<int> list;
    public List<object> listObject;

    [IterationSetup]
    public void Setup()
    {
        arrayList = new ArrayList();
        list = new List<int>();
        listObject = new List<object>();
    }

    [Benchmark]
    public ArrayList WriteArrayList()
    {
        for(int i=0; i < itemCount; i++)
        {
            arrayList.Add(i);
        }
        return arrayList;
    }

    [Benchmark]
    public List<object> WriteListObject()
    {
        for (int i = 0; i < itemCount; i++)
        {
            listObject.Add(i);
        }
        return listObject;
    }

    [Benchmark]
    public List<int> WriteList()
    {
        for (int i = 0; i < itemCount; i++)
        {
            list.Add(i);
        }
        return list;
    }
}

簡(jiǎn)單來(lái)說(shuō),我們正在循環(huán) 1000 萬(wàn)次并將項(xiàng)目??添加到列表中。結(jié)果是:

方法 平均 錯(cuò)誤 標(biāo)準(zhǔn)偏差
WriteArrayList 651.48 ms 4.215 ms 3.943 ms
WriteListObject 641.95 ms 5.129 ms 4.798 ms
WriteList 88.49 ms 5.631 ms 16.603 ms

不難看出這里的性能差異。我們可以看到 List 類型的對(duì)象也存在同樣的裝箱/拆箱問(wèn)題。

在較小程度上,讀取也會(huì)變慢,因?yàn)槟銓⒆x取一個(gè)對(duì)象,然后“拆箱”該對(duì)象并將其轉(zhuǎn)換為整數(shù)。

什么時(shí)候應(yīng)該使用 ArrayList?

絕不。

唯一應(yīng)該使用 ArrayList 的時(shí)候是使用在 List<T> 之前構(gòu)建的庫(kù)時(shí),我相信它是在 .NET 2.0 中引入的。如果你使用的是面向 .NET 1.0 或 1.1 的庫(kù)(或構(gòu)建代碼),那么我猜 ArrayList 沒(méi)問(wèn)題。

相關(guān)文章

標(biāo)簽: CSharp  Array  ArryList  List方法  代碼性能  優(yōu)化  
x
  • 站長(zhǎng)推薦
/* 左側(cè)顯示文章內(nèi)容目錄 */