Câu lệnh LINQ có nhanh hơn vòng lặp 'foreach' không?


124

Tôi đang viết một trình quản lý Kết xuất lưới và nghĩ rằng sẽ là một ý tưởng hay khi nhóm tất cả các mắt lưới sử dụng cùng một bộ đổ bóng và sau đó hiển thị chúng trong khi tôi đang ở trong bộ đổ bóng đó.

Tôi hiện đang sử dụng foreachvòng lặp, nhưng tự hỏi liệu việc sử dụng LINQ có thể giúp tôi tăng hiệu suất không?



1
Vui lòng cân nhắc đặt câu trả lời của @ MarcGravell thành câu được chấp nhận, có những trường hợp, ví dụ, linq thành sql, trong đó linq nhanh hơn for / foreach.
paqogomez

Câu trả lời:


222

Tại sao LINQ phải nhanh hơn? Nó cũng sử dụng các vòng lặp trong nội bộ.

Hầu hết các trường hợp, LINQ sẽ chậm hơn một chút vì nó giới thiệu chi phí. Không sử dụng LINQ nếu bạn quan tâm nhiều đến hiệu suất. Sử dụng LINQ vì bạn muốn mã ngắn hơn, dễ đọc hơn và có thể bảo trì.


7
Vì vậy, kinh nghiệm của bạn là LINQ nhanh hơn và làm cho mã khó đọc và khó bảo trì hơn? Vui lòng giải thích.
codymanix

87
Tôi nghĩ rằng bạn đã có nó lạc hậu. Anh ấy đang nói LINQ là SLOWER. Điều này là do quá đầu. Anh ấy cũng nói rằng LINQ dễ đọc và dễ bảo trì hơn.
Joseph McIntyre

5
Lấy làm tiếc. Trong khi chờ đợi, chúng tôi đã có rất nhiều thứ trong đó chúng tôi so sánh giữa linq và for or foreach performance, và hầu hết thời gian linq đều nhanh hơn.
Ưu đãi vào

34
Thành thật mà nói theo ý kiến ​​của tôi, một vòng lặp foreach dễ đọc hơn Phương pháp LINQ của nó. Tôi sử dụng LINQ vì nó thú vị :)
LuckyLikey

4
Có nhưng trong một số trường hợp, LINQ thực sự có thể cải thiện khả năng đọc, vì vậy hãy quên bình luận thiếu suy nghĩ của tôi đi <3
LuckyLikey

59

LINQ-to-Objects nói chung sẽ thêm một số chi phí biên (nhiều trình vòng lặp, v.v.). Nó vẫn phải thực hiện các vòng lặp, phải gọi ủy quyền, nói chung sẽ phải thực hiện thêm một số tham chiếu để truy cập các biến được nắm bắt, v.v. Trong hầu hết các mã, điều này sẽ hầu như không thể phát hiện được và nhiều khả năng hơn là mã dễ hiểu hơn.

Với các nhà cung cấp LINQ khác như LINQ-to-SQL, thì vì truy vấn có thể lọc tại máy chủ nên nó sẽ tốt hơn nhiều so với một căn hộ foreach, nhưng rất có thể bạn sẽ không thực hiện một cuộc kiểm tra "select * from foo" nào cả , vì vậy điều đó không nhất thiết phải là công bằng sự so sánh.

Tái PLINQ; song song có thể làm giảm thời gian trôi qua , nhưng tổng thời gian CPU thường sẽ tăng một chút do chi phí quản lý luồng, v.v.


Trong câu trả lời khác, bạn ám chỉ không sử dụng LINQ trên các bộ sưu tập trong bộ nhớ - ví dụ List<Foo>; thay vào đó, tôi nên sử dụng một foreachkhối trên các bộ sưu tập này. Khuyến nghị sử dụng foreachtrong những bối cảnh này có ý nghĩa. Mối quan tâm của tôi: tôi có nên chỉ thay thế các truy vấn LINQ bằng foreach nếu tôi phát hiện ra vấn đề về hiệu suất không? Về phía trước, tôi sẽ xem xét điều foreachđầu tiên.
IAbstract


15

LINQ bây giờ chậm hơn, nhưng nó có thể nhanh hơn vào một lúc nào đó. Điều tốt về LINQ là bạn không cần phải quan tâm đến cách nó hoạt động. Nếu một phương pháp mới được nghĩ ra cực kỳ nhanh, những người tại Microsoft có thể thực hiện nó mà không cần phải nói với bạn và mã của bạn sẽ nhanh hơn rất nhiều.

Tuy nhiên, quan trọng hơn, LINQ dễ đọc hơn nhiều. Đó là lý do đủ.


3
Tôi thích dòng "Microsoft có thể triển khai nó" có được không, ý tôi là có thể thực hiện được mà không cần nâng cấp khung không?
Shrivallabh

1
LINQ sẽ không bao giờ thực sự nhanh hơn triển khai gốc, vì vào cuối ngày, nó sẽ chuyển sang triển khai gốc. Không có lệnh CPU LINQ đặc biệt nào và thanh ghi LINQ có thể được sử dụng để dịch mã máy LINQ nhanh hơn - và nếu có, chúng cũng sẽ được sử dụng bởi mã không phải LINQ.
mg30rg

Không đúng, tại một số thời điểm các hoạt động liên kết nhất định có thể trở thành đa luồng hoặc thậm chí sử dụng GPU vào một số thời điểm.
John Stock



5

Tôi quan tâm đến câu hỏi này, vì vậy tôi đã làm một bài kiểm tra vừa rồi. Sử dụng .NET Framework 4.5.2 trên CPU Intel (R) Core (TM) i3-2328M @ 2.20GHz, 2200 Mhz, 2 Core với 8GB ram chạy Microsoft Windows 7 Ultimate.

Có vẻ như LINQ có thể nhanh hơn cho mỗi vòng lặp. Đây là kết quả tôi nhận được:

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

Sẽ rất thú vị nếu một số bạn có thể sao chép và dán mã này vào ứng dụng bảng điều khiển và thử nghiệm. Trước khi thử nghiệm với một đối tượng (Nhân viên), tôi đã thử thử nghiệm tương tự với số nguyên. Ở đó LINQ cũng nhanh hơn.

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

}

Đây là những gì tôi nhận được: Exists = True Time = 274 Exists = True Time = 314
PmanAce

2
bạn đã cân nhắc thực hiện linq trước rồi tính sau, nó cũng có thể tạo ra một số khác biệt
Muhammad Mamoor Khan

3
Hấp dẫn. Tôi nhận được Exists=True Time=184 Exists=True Time=135nó trên một máy tính xách tay Apache Gaming (Win 10, C # 7.3). Đã biên dịch và chạy ở chế độ gỡ lỗi. Nếu tôi đảo ngược các bài kiểm tra tôi nhận được Exists=True Time=158 Exists=True Time=194. Có vẻ như Linq được tối ưu hóa hơn tôi đoán.
James Wilkins

1
Có một sự hiểu lầm trong bài đăng này liên quan đến thử nghiệm đối tượng. Mặc dù chắc chắn là điều thú vị là List.Exists và .Contains dường như hoạt động tốt hơn foreach. Điều quan trọng cần lưu ý là .Exists không phải là một phương thức linq to entity và sẽ chỉ hoạt động trên các danh sách, phương thức tương đương linq của nó, .Any (), chắc chắn hoạt động chậm hơn foreach.
AbdulG

3

Đây thực sự là một câu hỏi khá phức tạp. Linq làm cho một số việc rất dễ thực hiện, mà nếu bạn tự thực hiện chúng, bạn có thể vấp phải (ví dụ: linq .Except ()). Điều này đặc biệt áp dụng cho PLinq, và đặc biệt là cho tập hợp song song do PLinq thực hiện.

Nói chung, đối với mã giống hệt nhau, linq sẽ chậm hơn, vì chi phí gọi đại biểu.

Tuy nhiên, nếu bạn đang xử lý một mảng lớn dữ liệu và áp dụng các phép tính tương đối đơn giản cho các phần tử, bạn sẽ nhận được sự gia tăng hiệu suất rất lớn nếu:

  1. Bạn sử dụng một mảng để lưu trữ dữ liệu.
  2. Bạn sử dụng vòng lặp for để truy cập từng phần tử (trái ngược với foreach hoặc linq).

    • Lưu ý: Khi đo điểm chuẩn, xin mọi người hãy nhớ - nếu bạn sử dụng cùng một mảng / danh sách cho hai bài kiểm tra liên tiếp, bộ nhớ đệm CPU sẽ làm cho bài kiểm tra thứ hai nhanh hơn. *
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.