ความแตกต่างของประสิทธิภาพสำหรับโครงสร้างควบคุม 'สำหรับ' และ 'foreach' ใน C #


105

ข้อมูลโค้ดใดจะให้ประสิทธิภาพดีกว่ากัน ส่วนโค้ดด้านล่างเขียนด้วย C #

1.

for(int counter=0; counter<list.Count; counter++)
{
    list[counter].DoSomething();
}

2.

foreach(MyType current in list)
{
    current.DoSomething();
}

31
ฉันจินตนาการว่ามันไม่สำคัญจริงๆ หากคุณมีปัญหาด้านประสิทธิภาพก็แทบจะไม่เกิดจากสาเหตุนี้ ไม่ใช่ว่าคุณไม่ควรถามคำถาม ...
darasd

2
เว้นแต่ว่าแอปของคุณจะมีประสิทธิภาพที่สำคัญมากฉันก็ไม่ต้องกังวลเรื่องนี้ ดีกว่าที่จะมีรหัสที่สะอาดและเข้าใจได้ง่าย
Fortyrunner

2
ฉันกังวลว่าคำตอบบางส่วนในที่นี้ดูเหมือนจะโพสต์โดยคนที่ไม่มีแนวคิดเรื่องตัววนซ้ำที่ใดในสมองของพวกเขาดังนั้นจึงไม่มีแนวคิดเกี่ยวกับตัวแจงนับหรือตัวชี้
Ed James

3
รหัสที่ 2 จะไม่คอมไพล์ System.Object ไม่มีสมาชิกที่เรียกว่า 'value' (เว้นแต่คุณจะชั่วร้ายจริงๆได้กำหนดเป็นวิธีการขยายและกำลังเปรียบเทียบผู้รับมอบสิทธิ์) พิมพ์ foreach ของคุณอย่างยิ่ง
Trillian

1
รหัสแรกจะไม่รวบรวมทั้งเว้นแต่ประเภทของlistจริงๆไม่ได้มีสมาชิกแทนcount Count
Jon Skeet

คำตอบ:


130

ส่วนหนึ่งขึ้นอยู่กับประเภทที่แน่นอนของlist. นอกจากนี้ยังขึ้นอยู่กับ CLR ที่คุณใช้

ไม่ว่าจะมีความสำคัญในทางใดก็ตามจะขึ้นอยู่กับว่าคุณกำลังทำงานจริงหรือไม่ ในเกือบทุกกรณีความแตกต่างของประสิทธิภาพจะไม่สำคัญ แต่ความแตกต่างของความสามารถในการอ่านจะสนับสนุนการforeachวนซ้ำ

ฉันใช้ LINQ เป็นการส่วนตัวเพื่อหลีกเลี่ยง "if" ด้วย:

foreach (var item in list.Where(condition))
{
}

แก้ไข: สำหรับพวกคุณที่อ้างว่าการทำซ้ำList<T>กับa foreachจะสร้างรหัสเดียวกับforลูปนี่คือหลักฐานว่ามันไม่:

static void IterateOverList(List<object> list)
{
    foreach (object o in list)
    {
        Console.WriteLine(o);
    }
}

ผลิต IL ของ:

.method private hidebysig static void  IterateOverList(class [mscorlib]System.Collections.Generic.List`1<object> list) cil managed
{
  // Code size       49 (0x31)
  .maxstack  1
  .locals init (object V_0,
           valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<object> V_1)
  IL_0000:  ldarg.0
  IL_0001:  callvirt   instance valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<!0> class [mscorlib]System.Collections.Generic.List`1<object>::GetEnumerator()
  IL_0006:  stloc.1
  .try
  {
    IL_0007:  br.s       IL_0017
    IL_0009:  ldloca.s   V_1
    IL_000b:  call       instance !0 valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<object>::get_Current()
    IL_0010:  stloc.0
    IL_0011:  ldloc.0
    IL_0012:  call       void [mscorlib]System.Console::WriteLine(object)
    IL_0017:  ldloca.s   V_1
    IL_0019:  call       instance bool valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<object>::MoveNext()
    IL_001e:  brtrue.s   IL_0009
    IL_0020:  leave.s    IL_0030
  }  // end .try
  finally
  {
    IL_0022:  ldloca.s   V_1
    IL_0024:  constrained. valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<object>
    IL_002a:  callvirt   instance void [mscorlib]System.IDisposable::Dispose()
    IL_002f:  endfinally
  }  // end handler
  IL_0030:  ret
} // end of method Test::IterateOverList

ถือว่าคอมไพเลอร์อาร์เรย์ที่แตกต่างกันแปลงforeachห่วงพื้นให้เป็นforห่วง List<T>แต่ไม่ได้ นี่คือรหัสเทียบเท่าสำหรับอาร์เรย์:

static void IterateOverArray(object[] array)
{
    foreach (object o in array)
    {
        Console.WriteLine(o);
    }
}

// Compiles into...

.method private hidebysig static void  IterateOverArray(object[] 'array') cil managed
{
  // Code size       27 (0x1b)
  .maxstack  2
  .locals init (object V_0,
           object[] V_1,
           int32 V_2)
  IL_0000:  ldarg.0
  IL_0001:  stloc.1
  IL_0002:  ldc.i4.0
  IL_0003:  stloc.2
  IL_0004:  br.s       IL_0014
  IL_0006:  ldloc.1
  IL_0007:  ldloc.2
  IL_0008:  ldelem.ref
  IL_0009:  stloc.0
  IL_000a:  ldloc.0
  IL_000b:  call       void [mscorlib]System.Console::WriteLine(object)
  IL_0010:  ldloc.2
  IL_0011:  ldc.i4.1
  IL_0012:  add
  IL_0013:  stloc.2
  IL_0014:  ldloc.2
  IL_0015:  ldloc.1
  IL_0016:  ldlen
  IL_0017:  conv.i4
  IL_0018:  blt.s      IL_0006
  IL_001a:  ret
} // end of method Test::IterateOverArray

ที่น่าสนใจฉันไม่พบเอกสารนี้ในข้อมูลจำเพาะ C # 3 ทุกที่ ...


Jon ไม่สนใจสถานการณ์ที่มี List <T> ด้านบน ... ใช้กับคอลเล็กชันอื่นด้วยหรือไม่? นอกจากนี้คุณรู้เรื่องนี้ได้อย่างไร (โดยไม่ได้มีเจตนามุ่งร้าย แต่อย่างใด) ... เช่นเดียวกับ .. คุณได้สะดุดสิ่งนี้อย่างแท้จริงขณะพยายามตอบคำถามนี้ก่อนหน้านี้เมื่อไม่นานมานี้? มันเป็นแบบสุ่ม / ความลับ :)
Pure.Krome

5
ฉันได้รับทราบเกี่ยวกับการเพิ่มประสิทธิภาพอาร์เรย์มาระยะหนึ่งแล้ว - อาร์เรย์เป็นคอลเลกชันประเภท "หลัก" คอมไพเลอร์ C # ตระหนักดีอยู่แล้วดังนั้นจึงเหมาะสมที่จะปฏิบัติต่อพวกเขาแตกต่างกัน คอมไพเลอร์ไม่มี (และไม่ควร) มีความรู้พิเศษเกี่ยวกับList<T>.
Jon Skeet

ไชโย :) และใช่ ... อาร์เรย์เป็นแนวคิดคอลเลกชันแรกที่ฉันได้รับการสอนเมื่อหลายปีก่อนที่ uni .. ดังนั้นมันจะทำให้รู้สึกว่าคอมไพเลอร์ฉลาดพอที่จะจัดการกับหนึ่งในประเภทดั้งเดิมที่สุด (ถ้าไม่ใช่) คอลเลกชัน ไชโยอีกครั้ง!
Pure.Krome

3
@JonSkeet การเพิ่มประสิทธิภาพตัววนซ้ำรายการออกไปจะเปลี่ยนลักษณะการทำงานเมื่อรายการถูกแก้ไขระหว่างการทำซ้ำ คุณสูญเสียข้อยกเว้นถ้าแก้ไข ยังคงเป็นไปได้ที่จะปรับให้เหมาะสม แต่ต้องตรวจสอบว่าไม่มีการแก้ไขใด ๆ เกิดขึ้น (รวมถึงเธรดอื่น ๆ ด้วย)
Craig Gidney

5
@VeeKeyBee: Microsoft กล่าวในปี 2547 ก) สิ่งต่าง ๆ เปลี่ยนไป ข) การทำงานจะต้องมีการทำเล็ก ๆปริมาณของการทำงานในแต่ละซ้ำสำหรับเรื่องนี้จะมีความสำคัญ โปรดทราบว่าforeachเหนืออาร์เรย์นั้นเทียบเท่ากับforอย่างไรก็ตาม ควรเขียนโค้ดเพื่อให้อ่านง่ายก่อนจากนั้นจึงปรับให้เหมาะสมเพียงเล็กน้อยเมื่อคุณมีหลักฐานว่าให้ประโยชน์ด้านประสิทธิภาพที่วัดได้
Jon Skeet

15

forวงได้รับเรียบเรียงรหัสประมาณเทียบเท่ากับนี้:

int tempCount = 0;
while (tempCount < list.Count)
{
    if (list[tempCount].value == value)
    {
        // Do something
    }
    tempCount++;
}

โดยที่เป็นforeachลูปถูกคอมไพล์เป็นโค้ดโดยประมาณเทียบเท่าสิ่งนี้:

using (IEnumerator<T> e = list.GetEnumerator())
{
    while (e.MoveNext())
    {
        T o = (MyClass)e.Current;
        if (row.value == value)
        {
            // Do something
        }
    }
}

ดังที่คุณเห็นทั้งหมดจะขึ้นอยู่กับวิธีการใช้งานตัวแจงนับเทียบกับวิธีการใช้งานตัวทำดัชนีรายการ ตามปกติแล้วตัวแจงนับสำหรับประเภทตามอาร์เรย์จะเขียนดังนี้:

private static IEnumerable<T> MyEnum(List<T> list)
{
    for (int i = 0; i < list.Count; i++)
    {
        yield return list[i];
    }
}

ดังที่คุณเห็นในกรณีนี้จะไม่สร้างความแตกต่างมากนัก แต่ตัวแจงนับสำหรับรายการที่เชื่อมโยงอาจมีลักษณะดังนี้:

private static IEnumerable<T> MyEnum(LinkedList<T> list)
{
    LinkedListNode<T> current = list.First;
    do
    {
        yield return current.Value;
        current = current.Next;
    }
    while (current != null);
}

ใน. NETคุณจะพบว่าคลาส LinkedList <T> ไม่มีแม้แต่ตัวสร้างดัชนีดังนั้นคุณจะไม่สามารถทำ for loop ในรายการที่เชื่อมโยงได้ แต่ถ้าทำได้ตัวสร้างดัชนีจะต้องเขียนดังนี้:

public T this[int index]
{
       LinkedListNode<T> current = this.First;
       for (int i = 1; i <= index; i++)
       {
            current = current.Next;
       }
       return current.value;
}

อย่างที่คุณเห็นการเรียกสิ่งนี้หลาย ๆ ครั้งในลูปนั้นจะช้ากว่าการใช้ตัวแจงนับที่จำได้ว่าอยู่ที่ไหนในรายการ


12

การทดสอบที่ง่ายในการตรวจสอบกึ่ง ฉันได้ทำการทดสอบเล็ก ๆ เพื่อดู นี่คือรหัส:

static void Main(string[] args)
{
    List<int> intList = new List<int>();

    for (int i = 0; i < 10000000; i++)
    {
        intList.Add(i);
    }

    DateTime timeStarted = DateTime.Now;
    for (int i = 0; i < intList.Count; i++)
    {
        int foo = intList[i] * 2;
        if (foo % 2 == 0)
        {
        }
    }

    TimeSpan finished = DateTime.Now - timeStarted;

    Console.WriteLine(finished.TotalMilliseconds.ToString());
    Console.Read();

}

และนี่คือส่วน foreach:

foreach (int i in intList)
{
    int foo = i * 2;
    if (foo % 2 == 0)
    {
    }
}

เมื่อฉันแทนที่ for ด้วย foreach - foreach เร็วขึ้น 20 มิลลิวินาที - สม่ำเสมออย่างต่อเนื่องสำหรับคือ 135-139ms ในขณะที่ foreach คือ 113-119ms ฉันสลับไปมาหลายครั้งเพื่อให้แน่ใจว่ามันไม่ใช่กระบวนการที่เพิ่งเริ่มต้น

อย่างไรก็ตามเมื่อฉันลบคำสั่ง foo และ if ออกไปค่า for นั้นเร็วขึ้น 30 ms (foreach คือ 88ms และเป็น 59ms) พวกเขาทั้งสองเป็นเปลือกหอยที่ว่างเปล่า ฉันสมมติว่า foreach ส่งผ่านตัวแปรโดยที่ for เป็นเพียงการเพิ่มตัวแปร ถ้าฉันเพิ่ม

int foo = intList[i];

จากนั้นให้ช้าลงประมาณ 30ms ฉันสมมติว่าสิ่งนี้เกี่ยวข้องกับการสร้าง foo และคว้าตัวแปรในอาร์เรย์และกำหนดให้กับ foo หากคุณเพิ่งเข้าถึง intList [i] คุณก็จะไม่มีบทลงโทษนั้น

ด้วยความสัตย์จริง .. ฉันคาดว่า foreach จะช้าลงเล็กน้อยในทุกสถานการณ์ แต่ไม่เพียงพอสำหรับการใช้งานส่วนใหญ่

แก้ไข: นี่คือรหัสใหม่โดยใช้คำแนะนำ Jons (134217728 เป็น int ที่ใหญ่ที่สุดที่คุณสามารถมีได้ก่อนที่ข้อยกเว้น System.OutOfMemory จะถูกโยนทิ้ง):

static void Main(string[] args)
{
    List<int> intList = new List<int>();

    Console.WriteLine("Generating data.");
    for (int i = 0; i < 134217728 ; i++)
    {
        intList.Add(i);
    }

    Console.Write("Calculating for loop:\t\t");

    Stopwatch time = new Stopwatch();
    time.Start();
    for (int i = 0; i < intList.Count; i++)
    {
        int foo = intList[i] * 2;
        if (foo % 2 == 0)
        {
        }
    }

    time.Stop();
    Console.WriteLine(time.ElapsedMilliseconds.ToString() + "ms");
    Console.Write("Calculating foreach loop:\t");
    time.Reset();
    time.Start();

    foreach (int i in intList)
    {
        int foo = i * 2;
        if (foo % 2 == 0)
        {
        }
    }

    time.Stop();

    Console.WriteLine(time.ElapsedMilliseconds.ToString() + "ms");
    Console.Read();
}

และนี่คือผลลัพธ์:

กำลังสร้างข้อมูล การคำนวณสำหรับลูป: 2458ms การคำนวณ foreach loop: 2005ms

การสลับไปมาเพื่อดูว่ามันเกี่ยวข้องกับลำดับของสิ่งต่างๆหรือไม่ให้ผลลัพธ์เหมือนกัน (เกือบ)


6
ใช้นาฬิกาจับเวลาดีกว่า DateTime ตอนนี้ - และฉันจะไม่เชื่อว่าการวิ่งเร็วขนาดนั้นพูดตามตรง
Jon Skeet

8
ลูป foreach ของคุณทำงานเร็วขึ้นเนื่องจาก 'for' จะประเมินเงื่อนไขการวนซ้ำแต่ละครั้ง ในกรณีตัวอย่างของคุณสิ่งนี้ทำให้มีการเรียกใช้เมธอดพิเศษหนึ่งรายการ (เพื่อรับ list.count) ในระยะสั้นคุณกำลังเปรียบเทียบโค้ดสองส่วนที่แตกต่างกันดังนั้นผลลัพธ์ที่แปลกประหลาดของคุณ ลอง 'int max = intlist.Count; สำหรับ (int i = 0; i <max; i ++) ... 'และลูป' for 'จะทำงานเร็วขึ้นตามที่คาดไว้เสมอ!
AR

1
หลังจากคอมไพล์แล้วสำหรับและ foreach จะปรับให้เหมาะสมกับสิ่งเดียวกันเมื่อทำงานกับ primitives จนกว่าคุณจะแนะนำ List <T> ว่าความเร็วต่างกัน (มาก)
แอนโธนีรัสเซล

9

หมายเหตุ: คำตอบนี้ใช้กับ Java ได้มากกว่า C # เนื่องจาก C # ไม่มีตัวทำดัชนีLinkedListsแต่ฉันคิดว่าประเด็นทั่วไปยังคงมีอยู่

ถ้า listคุณกำลังทำงานอยู่เกิดขึ้นเป็น a LinkedListประสิทธิภาพของรหัสดัชนี ( การเข้าถึงแบบอาร์เรย์ ) จะแย่กว่าการใช้IEnumeratorจากforeachรายการขนาดใหญ่มาก

เมื่อคุณเข้าถึงองค์ประกอบ 10.000 LinkedListโดยใช้ไวยากรณ์ตัวทำดัชนี: list[10000]รายการที่เชื่อมโยงจะเริ่มต้นที่โหนดส่วนหัวและข้ามไปที่Next-pointer หนึ่งหมื่นครั้งจนกว่าจะถึงวัตถุที่ถูกต้อง เห็นได้ชัดว่าหากคุณทำสิ่งนี้แบบวนซ้ำคุณจะได้รับ:

list[0]; // head
list[1]; // head.Next
list[2]; // head.Next.Next
// etc.

เมื่อคุณโทร GetEnumerator (โดยปริยายโดยใช้forach-syntax) คุณจะได้รับIEnumeratorวัตถุที่มีตัวชี้ไปที่โหนดหัว ทุกครั้งที่คุณโทรMoveNextตัวชี้นั้นจะถูกย้ายไปยังโหนดถัดไปดังนี้:

IEnumerator em = list.GetEnumerator();  // Current points at head
em.MoveNext(); // Update Current to .Next
em.MoveNext(); // Update Current to .Next
em.MoveNext(); // Update Current to .Next
// etc.

อย่างที่คุณเห็นในกรณีของLinkedLists เมธอดตัวทำดัชนีอาร์เรย์จะช้าลงและช้าลงยิ่งคุณวนซ้ำนานขึ้น (ต้องผ่านตัวชี้หัวเดียวกันซ้ำแล้วซ้ำเล่า) ในขณะที่IEnumerableทำงานในเวลาคงที่

แน่นอนอย่างที่จอนพูดสิ่งนี้ขึ้นอยู่กับประเภทของlistถ้าlistไม่ใช่ a LinkedListแต่เป็นอาร์เรย์พฤติกรรมจะแตกต่างกันอย่างสิ้นเชิง


4
LinkedList ใน. NET ไม่มีตัวสร้างดัชนีดังนั้นจึงไม่ใช่ตัวเลือก
Jon Skeet

โอ้ดีที่แก้ปัญหานั้น :-) ฉันแค่ดูLinkedList<T>เอกสารบน MSDN และมี API ที่ดีทีเดียว ที่สำคัญที่สุดคือไม่มีget(int index)วิธีการเช่นเดียวกับ Java แต่ถึงกระนั้นผมคิดว่าจุดยังคงถือสำหรับรายชื่อเหมือนโครงสร้างข้อมูลอื่น ๆ ที่ exposes IEnumeratorดัชนีที่ช้ากว่าที่เฉพาะเจาะจงหนึ่ง
Tom Lokhorst

2

เช่นเดียวกับที่คนอื่น ๆ พูดถึงแม้ว่าประสิทธิภาพจะไม่สำคัญมากนัก foreach มักจะช้าลงเล็กน้อยเนื่องจากIEnumerable/ IEnumeratorการใช้งานในลูป คอมไพลเลอร์จะแปลโครงสร้างเป็นการเรียกบนอินเทอร์เฟซนั้นและสำหรับทุกขั้นตอนจะมีการเรียกใช้ฟังก์ชัน + คุณสมบัติในโครงสร้าง foreach

IEnumerator iterator = ((IEnumerable)list).GetEnumerator();
while (iterator.MoveNext()) {
  var item = iterator.Current;
  // do stuff
}

นี่คือการขยายตัวที่เทียบเท่ากันของโครงสร้างใน C # คุณสามารถจินตนาการได้ว่าผลกระทบด้านประสิทธิภาพจะแตกต่างกันไปอย่างไรโดยขึ้นอยู่กับการใช้งาน MoveNext และ Current ในขณะที่ในการเข้าถึงอาร์เรย์คุณไม่มีการอ้างอิงนั้น


4
อย่าลืมว่ามีความแตกต่างระหว่างการเข้าถึงอาร์เรย์และการเข้าถึงดัชนี หากลิสต์อยู่List<T>ที่นี่แสดงว่ายังคงมีการเรียกใช้ตัวสร้างดัชนี มันไม่เหมือนกับการเข้าถึงอาร์เรย์โลหะเปล่า
Jon Skeet

จริงแท้แน่นอน! ยังเป็นอีกหนึ่งการดำเนินการเกี่ยวกับทรัพย์สินและเราอยู่ในความเมตตาของการนำไปใช้
Charles Prakash Dasari

1

หลังจากอ่านข้อโต้แย้งมากพอแล้วว่า "foreach loop ควรเป็นที่ต้องการเพื่อให้อ่านง่าย" ฉันสามารถพูดได้ว่าปฏิกิริยาแรกของฉันคือ "อะไร"? โดยทั่วไปแล้วความสามารถในการอ่านจะเป็นแบบอัตนัยและโดยเฉพาะอย่างยิ่งเช่นนี้ สำหรับคนที่มีพื้นฐานในการเขียนโปรแกรม (จริงๆแล้วทุกภาษาก่อน Java) สำหรับลูปนั้นอ่านง่ายกว่า foreach ลูปมาก นอกจากนี้คนกลุ่มเดียวกันที่อ้างว่า foreach loops อ่านได้ง่ายกว่ายังสนับสนุน linq และ "คุณสมบัติ" อื่น ๆ ที่ทำให้โค้ดอ่านและบำรุงรักษายากซึ่งเป็นสิ่งที่พิสูจน์ประเด็นข้างต้น

เกี่ยวกับผลกระทบต่อประสิทธิภาพการทำงานให้ดูคำตอบนี้คำถาม

แก้ไข: มีคอลเล็กชันใน C # (เช่น HashSet) ที่ไม่มีตัวสร้างดัชนี ในคอลเลกชันเหล่านี้foreachเป็นวิธีเดียวที่จะย้ำและมันก็เป็นกรณีเดียวที่ฉันคิดว่ามันควรจะใช้มากกว่าสำหรับ


0

มีข้อเท็จจริงที่น่าสนใจเพิ่มเติมซึ่งอาจพลาดได้ง่ายเมื่อทดสอบความเร็วของลูปทั้งสอง: การใช้โหมดดีบักไม่อนุญาตให้คอมไพเลอร์ปรับแต่งโค้ดโดยใช้การตั้งค่าเริ่มต้น

สิ่งนี้ทำให้ฉันได้ผลลัพธ์ที่น่าสนใจที่ foreach เร็วกว่าในโหมดดีบัก ในขณะที่ for ist เร็วกว่า foreach ในโหมด release เห็นได้ชัดว่าคอมไพเลอร์มีวิธีที่ดีกว่าในการเพิ่มประสิทธิภาพสำหรับลูปมากกว่า foreach loop ซึ่งทำให้การเรียกใช้เมธอดหลาย ๆ สำหรับลูปเป็นพื้นฐานที่เป็นไปได้ว่าซีพียูได้รับการปรับให้เหมาะสมด้วยซ้ำ


0

ในตัวอย่างที่คุณให้เป็นที่แน่นอนดีกว่าที่จะใช้foreachห่วงแทนforห่วง

โครงสร้างมาตรฐานforeachสามารถทำได้เร็วกว่า (1,5 รอบต่อขั้นตอน) มากกว่าแบบธรรมดาfor-loop(2 รอบต่อขั้นตอน) เว้นแต่จะคลายการวนซ้ำแล้ว (1.0 รอบต่อขั้นตอน)

ดังนั้นสำหรับรหัสประจำวันประสิทธิภาพการทำงานไม่ได้เป็นเหตุผลที่จะใช้ที่ซับซ้อนมากขึ้นfor, whileหรือdo-whileโครงสร้าง

ตรวจสอบลิงค์นี้: http://www.codeproject.com/Articles/146797/Fast-and-Less-Fast-Loops-in-C


╔══════════════════════╦═══════════╦═══════╦════════════════════════╦═════════════════════╗
        Method         List<int>  int[]  Ilist<int> onList<Int>  Ilist<int> on int[] 
╠══════════════════════╬═══════════╬═══════╬════════════════════════╬═════════════════════╣
 Time (ms)             23,80      17,56  92,33                   86,90               
 Transfer rate (GB/s)  2,82       3,82   0,73                    0,77                
 % Max                 25,2%      34,1%  6,5%                    6,9%                
 Cycles / read         3,97       2,93   15,41                   14,50               
 Reads / iteration     16         16     16                      16                  
 Cycles / iteration    63,5       46,9   246,5                   232,0               
╚══════════════════════╩═══════════╩═══════╩════════════════════════╩═════════════════════╝


4
คุณอาจอ่านบทความโครงการรหัสที่คุณเชื่อมโยงอีกครั้ง เป็นบทความที่น่าสนใจ แต่ตรงข้ามกับโพสต์ของคุณ นอกจากนี้ตารางที่คุณสร้างขึ้นใหม่กำลังวัดประสิทธิภาพของการเข้าถึงอาร์เรย์และรายการโดยตรงหรือผ่านอินเทอร์เฟซ IList ไม่มีอะไรเกี่ยวข้องกับคำถาม :)
Paul Walls

0

คุณสามารถอ่านเกี่ยวกับเรื่องนี้ได้ใน Deep .NET - ตอนที่ 1 การวนซ้ำ

มันครอบคลุมผลลัพธ์ (โดยไม่ต้องเริ่มต้นครั้งแรก) จากซอร์สโค้ด. NET ไปจนถึงการถอดชิ้นส่วน

ตัวอย่างเช่น - การวนซ้ำอาร์เรย์ด้วย foreach loop: ป้อนคำอธิบายภาพที่นี่

และ - แสดงรายการซ้ำด้วย foreach loop: ป้อนคำอธิบายภาพที่นี่

และผลลัพธ์สุดท้าย: ป้อนคำอธิบายภาพที่นี่

ป้อนคำอธิบายภาพที่นี่

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.