Apakah pernyataan LINQ lebih cepat daripada loop 'foreach'?

124

Saya sedang menulis manajer Mesh Rendering dan berpikir itu akan menjadi ide yang baik untuk mengelompokkan semua mesh yang menggunakan shader yang sama dan kemudian membuat ini saat saya dalam shader pass.

Saat ini saya menggunakan foreachloop, tetapi bertanya-tanya apakah menggunakan LINQ dapat meningkatkan kinerja saya?

Neil Knight
sumber
1
Harap pertimbangkan untuk menyetel jawaban @ MarcGravell ke jawaban yang diterima, ada situasi, linq ke sql misalnya, di mana linq lebih cepat daripada for / foreach.
paqogomez

Jawaban:

222

Mengapa LINQ harus lebih cepat? Ini juga menggunakan loop secara internal.

Seringkali, LINQ akan menjadi sedikit lebih lambat karena menyebabkan overhead. Jangan gunakan LINQ jika Anda sangat peduli dengan performa. Gunakan LINQ karena Anda ingin kode yang lebih pendek dapat dibaca dan dipelihara dengan lebih baik.

codymanix.dll
sumber
7
Jadi menurut pengalaman Anda, LINQ lebih cepat dan membuat kode lebih sulit dibaca dan dikelola? Tolong jelaskan.
codymanix
87
Saya pikir Anda memilikinya mundur. Dia mengatakan LINQ lebih lambat. Ini karena over head. Dia juga mengatakan bahwa LINQ lebih mudah dibaca dan dipelihara.
Joseph McIntyre
5
Maaf. Sementara itu kami memiliki banyak hal di mana kami membandingkan LINQ dan untuk atau meningkatkan kinerja, dan sebagian besar waktu LINQ lebih cepat.
Offler
34
Sejujurnya menurut saya, foreach loop lebih mudah dibaca daripada Metode LINQ-nya. Saya menggunakan LINQ karena itu keren :)
LuckyLikey
4
Ya, tetapi dalam beberapa kasus LINQ benar-benar dapat meningkatkan keterbacaan, jadi lupakan komentar saya yang ceroboh <3
LuckyLikey
59

LINQ-to-Objects umumnya akan menambahkan beberapa overhead marginal (beberapa iterator, dll). Ia masih harus melakukan loop, dan memiliki pemanggilan delegasi, dan umumnya harus melakukan beberapa dereferensi tambahan untuk mendapatkan variabel yang ditangkap, dll. Dalam kebanyakan kode ini hampir tidak dapat dideteksi, dan lebih dari yang diberikan oleh kode yang lebih sederhana untuk dipahami.

Dengan penyedia LINQ lain seperti LINQ-to-SQL, maka sejak query dapat menyaring di server itu harus jauh lebih baik daripada flat foreach, tapi kemungkinan besar Anda tidak akan dilakukan selimut "select * from foo" pula , sehingga tidak selalu adil perbandingan.

Re PLINQ; paralelisme dapat mengurangi waktu yang telah berlalu , tetapi total waktu CPU biasanya akan meningkat sedikit karena overhead manajemen utas, dll.

Marc Gravell
sumber
Dalam jawaban lain Anda menyinggung untuk tidak menggunakan LINQ pada koleksi dalam memori - mis List<Foo>; sebagai gantinya, saya harus menggunakan foreachblok pada koleksi ini. Rekomendasi untuk digunakan foreachdalam konteks ini memang masuk akal. Kekhawatiran saya: haruskah saya mengganti kueri LINQ dengan foreach jika saya mendeteksi masalah kinerja? Ke depan, saya akan mempertimbangkan yang foreachpertama.
IAbstract
19

Saya pikir LINQ lebih baik digunakan melalui foreachloop, karena LINQ memberi Anda kode yang lebih bersih dan mudah dipahami. Tapi LINQ lebih lambat dari foreach. Untuk mendapatkan lebih banyak, baca artikel LINQ vs FOREACH vs FOR Loop Performance .

Pranay Rana
sumber
15

LINQ lebih lambat sekarang, tetapi mungkin menjadi lebih cepat di beberapa titik. Hal yang baik tentang LINQ adalah Anda tidak perlu peduli tentang cara kerjanya. Jika metode baru dipikirkan dengan sangat cepat, orang-orang di Microsoft dapat menerapkannya bahkan tanpa memberi tahu Anda dan kode Anda akan jauh lebih cepat.

Lebih penting lagi, LINQ jauh lebih mudah dibaca. Itu seharusnya menjadi alasan yang cukup.

Jouke van der Maas
sumber
3
Saya suka baris "Microsoft dapat mengimplementasikannya" apakah mungkin, maksud saya apakah mungkin tanpa saya mengupgrade kerangka kerja?
Shrivallabh
1
LINQ tidak akan pernah menjadi lebih cepat dari implementasi native, karena pada akhirnya, LINQ diterjemahkan menjadi implementasi native. Tidak ada instruksi CPU LINQ khusus dan register LINQ yang dapat digunakan untuk menerjemahkan kode mesin LINQ yang lebih cepat - dan jika ada, instruksi tersebut akan digunakan oleh kode non-LINQ juga.
mg30rg
Tidak benar, di beberapa titik operasi tautan tertentu dapat menjadi multi-utas atau bahkan menggunakan GPU di beberapa titik.
John Stock
9

Anda mungkin mendapatkan peningkatan kinerja jika Anda menggunakan LINQ paralel untuk multi core. Lihat Parallel LINQ (PLINQ) (MSDN).

mcintyre321
sumber
5

Saya tertarik dengan pertanyaan ini, jadi saya melakukan tes sekarang. Menggunakan .NET Framework 4.5.2 pada Intel (R) Core (TM) i3-2328M CPU @ 2.20GHz, 2200 Mhz, 2 Core (s) dengan ram 8GB yang menjalankan Microsoft Windows 7 Ultimate.

Sepertinya LINQ mungkin lebih cepat daripada untuk setiap loop. Inilah hasil yang saya dapatkan:

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

Akan menarik jika beberapa dari Anda dapat menyalin & menempel kode ini di aplikasi konsol dan mengujinya juga. Sebelum menguji dengan objek (Karyawan) saya mencoba tes yang sama dengan bilangan bulat. LINQ juga lebih cepat di sana.

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

}
Theo Kand.
sumber
Inilah yang saya dapatkan: Exists = True Time = 274 Exists = True Time = 314
PmanAce
2
Pernahkah Anda mempertimbangkan untuk melakukan linq terlebih dahulu dan selanjutnya nanti, mungkin akan membuat perbedaan juga
Muhammad Mamoor Khan
3
Menarik. Saya mendapatkannya Exists=True Time=184 Exists=True Time=135di laptop Apache Gaming (Win 10, C # 7.3). Dikompilasi dan dijalankan dalam mode debug. Jika saya membalik tes yang saya dapatkan Exists=True Time=158 Exists=True Time=194. Sepertinya Linq lebih dioptimalkan saya kira.
James Wilkins
1
Ada kesalahpahaman dalam postingan ini tentang tes objek. Meskipun sangat menarik bahwa List.Exists dan .Contains tampaknya berkinerja lebih baik daripada foreach. Penting untuk dicatat bahwa .Exists bukanlah metode linq ke entitas dan hanya akan bekerja pada daftar, metode setara linq-nya, .Any (), pasti berkinerja lebih lambat daripada foreach.
AbdulG
3

Ini sebenarnya pertanyaan yang cukup kompleks. Linq membuat hal-hal tertentu sangat mudah dilakukan, bahwa jika Anda menerapkannya sendiri, Anda mungkin tersandung (misalnya linq .Except ()). Ini terutama berlaku untuk PLinq, dan terutama untuk agregasi paralel seperti yang diterapkan oleh PLinq.

Secara umum, untuk kode identik, linq akan lebih lambat, karena overhead pemanggilan delegasi.

Namun, jika Anda memproses data dalam jumlah besar, dan menerapkan penghitungan yang relatif sederhana ke elemen, Anda akan mendapatkan peningkatan performa yang sangat besar jika:

  1. Anda menggunakan array untuk menyimpan data.
  2. Anda menggunakan perulangan for untuk mengakses setiap elemen (sebagai lawan foreach atau linq).

    • Catatan: Saat melakukan benchmarking, harap semua orang ingat - jika Anda menggunakan array / daftar yang sama untuk dua pengujian berturut-turut, cache CPU akan membuat pengujian kedua lebih cepat. *
Adam Brown
sumber