คำสั่ง LINQ เร็วกว่าลูป 'foreach' หรือไม่?


124

ฉันกำลังเขียนตัวจัดการ Mesh Rendering และคิดว่ามันเป็นความคิดที่ดีที่จะจัดกลุ่มตาข่ายทั้งหมดที่ใช้ shader เดียวกันแล้วแสดงผลสิ่งเหล่านี้ในขณะที่ฉันอยู่ใน shader pass นั้น

ฉันกำลังใช้foreachลูปอยู่ แต่สงสัยว่าการใช้ LINQ อาจทำให้ฉันมีประสิทธิภาพเพิ่มขึ้นหรือไม่?


1
เป็นไปได้ที่จะซ้ำกันของประสิทธิภาพ"Nested foreach" เทียบกับ "lambda / linq query" (LINQ-to-Objects)
Daniel Earwicker

1
โปรดพิจารณาการตั้งค่าคำตอบของ @ MarcGravell สำหรับคำตอบที่ยอมรับมีสถานการณ์เช่น linq ถึง sql ที่ linq เร็วกว่า for / foreach
paqogomez

คำตอบ:


222

ทำไม LINQ ถึงเร็วกว่า? นอกจากนี้ยังใช้ลูปภายใน

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


7
ดังนั้นประสบการณ์ของคุณคือ LINQ เร็วกว่าและทำให้โค้ดอ่านยากขึ้นและต้องดูแลรักษา? กรุณาอธิบาย.
codymanix

87
ฉันคิดว่าคุณคิดย้อนหลังไปแล้ว เขากำลังบอกว่า LINQ เป็น SLOWER นี่คือสาเหตุที่ศีรษะ เขายังบอกด้วยว่า LINQ อ่านและดูแลรักษาง่ายกว่า
Joseph McIntyre

5
ขอโทษ ในระหว่างนี้เรามีหลายสิ่งหลายอย่างที่เราเปรียบเทียบ linq และ for หรือ foreach performance และ linq ส่วนใหญ่เร็วกว่า
Offler

34
พูดตามตรงในความคิดของฉัน foreach loop อ่านได้ง่ายกว่าวิธี LINQ ฉันใช้ LINQ เพราะมันเจ๋ง :)
LuckyLikey

4
ใช่ แต่ในบางกรณี LINQ อาจปรับปรุงความสามารถในการอ่านได้จริงๆดังนั้นอย่าลืมความคิดเห็นของฉันไป <3
LuckyLikey

60

LINQ-to-Objects โดยทั่วไปจะเพิ่มค่าโสหุ้ยเล็กน้อย (ตัวทำซ้ำหลายตัว ฯลฯ ) มันยังคงต้องทำลูปและมีการเรียกผู้ร่วมประชุมและโดยทั่วไปจะต้องทำการอ้างอิงพิเศษบางอย่างเพื่อให้ได้ตัวแปรที่จับได้เป็นต้นในโค้ดส่วนใหญ่สิ่งนี้แทบจะไม่สามารถตรวจจับได้และมากกว่าที่โค้ดที่เข้าใจง่ายกว่า

กับผู้ให้บริการอื่น ๆ เช่น LINQ LINQ เพื่อ SQL แล้วตั้งแต่แบบสอบถามสามารถกรองที่เซิร์ฟเวอร์ที่ควรจะเป็นมากดีกว่ากว่าแบนforeachแต่ส่วนใหญ่มีแนวโน้มที่คุณจะไม่ได้ทำผ้าห่ม"select * from foo" อยู่แล้วดังนั้นที่ไม่จำเป็นต้องยุติธรรม การเปรียบเทียบ

เรื่อง PLINQ; ความขนานอาจลดเวลาที่ผ่านไปแต่เวลา CPU ทั้งหมดมักจะเพิ่มขึ้นเล็กน้อยเนื่องจากค่าใช้จ่ายในการจัดการเธรดเป็นต้น


ในอีกคำตอบหนึ่งที่คุณอ้างว่าไม่ใช้ LINQ ในคอลเล็กชันในหน่วยความจำเช่นList<Foo>; ฉันควรใช้foreachบล็อกในคอลเล็กชันเหล่านี้แทน คำแนะนำที่จะใช้foreachในบริบทเหล่านี้มีเหตุผล ข้อกังวลของฉัน: ฉันควรแทนที่คำค้นหา LINQ เท่านั้นforeach หากตรวจพบปัญหาด้านประสิทธิภาพหรือไม่ ก้าวต่อไปฉันจะพิจารณาอย่างforeachแรก
IAbstract

19

ฉันคิดว่า LINQ ดีกว่าที่จะใช้แบบforeachวนซ้ำเพราะให้โค้ดที่สะอาดและเข้าใจง่ายกว่ามาก แต่ LINQ ช้ากว่าforeach. จะได้รับเพิ่มเติมไปผ่านบทความLINQ VS foreach เทียบกับผลการดำเนินงานสำหรับวง


15

ตอนนี้ LINQ ช้าลง แต่อาจเร็วขึ้นในบางจุด ข้อดีของ LINQ คือคุณไม่ต้องสนใจว่ามันจะทำงานอย่างไร หากมีการคิดวิธีการใหม่ที่รวดเร็วอย่างไม่น่าเชื่อผู้คนใน Microsoft สามารถนำไปใช้ได้โดยไม่ต้องบอกคุณและรหัสของคุณจะเร็วขึ้นมาก

ที่สำคัญกว่านั้น LINQ นั้นอ่านง่ายกว่ามาก นั่นน่าจะเป็นเหตุผลเพียงพอ


3
ฉันชอบบรรทัด "Microsoft สามารถใช้งานได้" เป็นไปได้หรือไม่ฉันหมายความว่าเป็นไปได้โดยไม่ต้องอัปเกรดกรอบงาน
Shrivallabh

1
LINQ จะไม่เร็วไปกว่าการใช้งานแบบเนทีฟเลยเนื่องจากในตอนท้ายของวันจะแปลเป็นการใช้งานแบบเนทีฟ ไม่มีคำแนะนำพิเศษของ LINQ CPU และการลงทะเบียน LINQ ที่สามารถใช้ในการแปลรหัสเครื่อง LINQ ได้เร็วขึ้นและหากมีก็จะใช้รหัสที่ไม่ใช่ LINQ ด้วย
mg30rg

ไม่จริงในบางจุดการดำเนินการลิงก์บางอย่างอาจกลายเป็นมัลติเธรดหรือแม้กระทั่งใช้ GPU ในบางจุด
John Stock

11

ควรสังเกตว่าforลูปเร็วกว่าforeach. ดังนั้นสำหรับโพสต์ต้นฉบับหากคุณกังวลเกี่ยวกับประสิทธิภาพขององค์ประกอบที่สำคัญเช่นตัวแสดงผลให้ใช้forลูป

ข้อมูลอ้างอิง: ใน. NET ลูปใดทำงานเร็วกว่า 'for' หรือ 'foreach'



5

ฉันสนใจคำถามนี้ดังนั้นฉันจึงทำการทดสอบในตอนนี้ การใช้. NET Framework 4.5.2 บน Intel (R) Core (TM) i3-2328M CPU @ 2.20GHz, 2200 Mhz, 2 Core (s) พร้อม RAM 8GB ที่รัน Microsoft Windows 7 Ultimate

ดูเหมือนว่า LINQ อาจเร็วกว่าสำหรับแต่ละลูป นี่คือผลลัพธ์ที่ฉันได้รับ:

Exists = True
Time   = 174
Exists = True
Time   = 149

มันจะน่าสนใจถ้าพวกคุณบางคนสามารถคัดลอกและวางโค้ดนี้ในแอพคอนโซลและทดสอบได้เช่นกัน ก่อนที่จะทดสอบกับวัตถุ (พนักงาน) ฉันได้ลองทดสอบแบบเดียวกันกับจำนวนเต็ม LINQ ก็เร็วขึ้นเช่นกัน

public class Program
{
    public class Employee
    {
        public int id;
        public string name;
        public string lastname;
        public DateTime dateOfBirth;

        public Employee(int id,string name,string lastname,DateTime dateOfBirth)
        {
            this.id = id;
            this.name = name;
            this.lastname = lastname;
            this.dateOfBirth = dateOfBirth;

        }
    }

    public static void Main() => StartObjTest();

    #region object test

    public static void StartObjTest()
    {
        List<Employee> items = new List<Employee>();

        for (int i = 0; i < 10000000; i++)
        {
            items.Add(new Employee(i,"name" + i,"lastname" + i,DateTime.Today));
        }

        Test3(items, items.Count-100);
        Test4(items, items.Count - 100);

        Console.Read();
    }


    public static void Test3(List<Employee> items, int idToCheck)
    {

        Stopwatch s = new Stopwatch();
        s.Start();

        bool exists = false;
        foreach (var item in items)
        {
            if (item.id == idToCheck)
            {
                exists = true;
                break;
            }
        }

        Console.WriteLine("Exists=" + exists);
        Console.WriteLine("Time=" + s.ElapsedMilliseconds);

    }

    public static void Test4(List<Employee> items, int idToCheck)
    {

        Stopwatch s = new Stopwatch();
        s.Start();

        bool exists = items.Exists(e => e.id == idToCheck);

        Console.WriteLine("Exists=" + exists);
        Console.WriteLine("Time=" + s.ElapsedMilliseconds);

    }

    #endregion


    #region int test
    public static void StartIntTest()
    {
        List<int> items = new List<int>();

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

        Test1(items, -100);
        Test2(items, -100);

        Console.Read();
    }

    public static void Test1(List<int> items,int itemToCheck)
    {

        Stopwatch s = new Stopwatch();
        s.Start();

        bool exists = false;
        foreach (var item in items)
        {
            if (item == itemToCheck)
            {
                exists = true;
                break;
            }
        }

        Console.WriteLine("Exists=" + exists);
        Console.WriteLine("Time=" + s.ElapsedMilliseconds);

    }

    public static void Test2(List<int> items, int itemToCheck)
    {

        Stopwatch s = new Stopwatch();
        s.Start();

        bool exists = items.Contains(itemToCheck);

        Console.WriteLine("Exists=" + exists);
        Console.WriteLine("Time=" + s.ElapsedMilliseconds);

    }

    #endregion

}

นี่คือสิ่งที่ฉันได้รับ: Exists = True Time = 274 Exists = True Time = 314
PmanAce

2
คุณเคยพิจารณาที่จะทำ linq ก่อนและนำหน้ามาใช้ในภายหลังมันอาจสร้างความแตกต่างได้เช่นกัน
มูฮัมหมัดมามูร์ข่าน

3
น่าสนใจ ฉันได้รับExists=True Time=184 Exists=True Time=135มันมาจากแล็ปท็อป Apache Gaming (Win 10, C # 7.3) คอมไพล์และรันในโหมดดีบัก Exists=True Time=158 Exists=True Time=194ถ้าผมย้อนกลับการทดสอบที่ฉันได้รับ ดูเหมือนว่า Linq จะเหมาะสมกว่าฉันเดา
James Wilkins

1
มีความเข้าใจผิดในโพสต์นี้เกี่ยวกับการทดสอบวัตถุ แม้ว่าจะเป็นเรื่องที่น่าสนใจ แต่ List.Exists และ .Contains ดูเหมือนจะทำงานได้ดีกว่า foreach สิ่งสำคัญคือต้องทราบว่า Exists ไม่ใช่วิธี linq to entities และจะใช้ได้เฉพาะกับรายการเท่านั้นซึ่งเป็นวิธีการเทียบเท่า linq เท่านั้น () ใด ๆ ทำงานได้ช้ากว่า foreach
AbdulG

3

นี่เป็นคำถามที่ค่อนข้างซับซ้อน Linq ทำให้บางสิ่งง่ายมากที่จะทำถ้าคุณนำไปใช้ด้วยตัวเองคุณอาจสะดุด (เช่น linq .Except ()) โดยเฉพาะอย่างยิ่งนี้ใช้กับ PLinq และโดยเฉพาะอย่างยิ่งกับการรวมแบบขนานที่ใช้โดย PLinq

โดยทั่วไปสำหรับรหัสที่เหมือนกัน linq จะทำงานช้าลงเนื่องจากค่าใช้จ่ายในการเรียกผู้ร่วมประชุม

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

  1. คุณใช้อาร์เรย์เพื่อจัดเก็บข้อมูล
  2. คุณใช้ for loop เพื่อเข้าถึงแต่ละองค์ประกอบ (ตรงข้ามกับ foreach หรือ linq)

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