2013-02-15 33 views
27

Câu hỏi rất ngắn gọn. Tôi có một mảng chuỗi được sắp xếp ngẫu nhiên (các mục 100K +), nơi tôi muốn tìm sự xuất hiện đầu tiên của một chuỗi mong muốn. Tôi có hai giải pháp.Đối với Linq - Hiệu suất so với Tương lai

Từ khi đọc những gì tôi có thể đoán là 'for loop' sẽ cho hiệu suất tốt hơn một chút (nhưng lề này luôn có thể thay đổi), nhưng tôi cũng thấy phiên bản LINQ dễ đọc hơn nhiều. Trên số dư mà phương pháp thường được coi là thực hành mã hóa tốt nhất hiện tại và tại sao?

string matchString = "dsf897sdf78"; 
int matchIndex = -1; 
for(int i=0; i<array.length; i++) 
{ 
    if(array[i]==matchString) 
    { 
     matchIndex = i; 
     break; 
    } 
} 

hoặc

int matchIndex = array.Select((r, i) => new { value = r, index = i }) 
         .Where(t => t.value == matchString) 
         .Select(s => s.index).First(); 
+0

Related: [for vs. foreach vs. LINQ] (http://programmers.stackexchange.com/questions/178218/for-vs-foreach-vs-linq) – sloth

+3

Tôi thậm chí sẽ không sử dụng LINQ trong này trường hợp, vì bạn thực sự phải chiến đấu để tìm chỉ mục - tôi muốn sử dụng 'Array.IndexOf' :) – Rawling

+0

Tôi sử dụng LINQ trên datatables lớn (100k + hồ sơ, ~ 40 cột) mà không có bất kỳ vấn đề hiệu suất. – Teejay

Trả lời

41

Các thực hành tốt nhất phụ thuộc vào những gì bạn cần:

  1. tốc độ phát triển và bảo trì: LINQ
  2. Hiệu suất (theo công cụ profiling): thủ công đang

LINQ thực sự làm những điều chậm với tất cả các indirection. Đừng lo lắng về điều đó vì 99% mã của bạn không ảnh hưởng đến hiệu suất của người dùng cuối.

Tôi bắt đầu với C++ và thực sự đã học cách tối ưu hóa một đoạn mã. LINQ không phù hợp để tận dụng tối đa CPU của bạn. Vì vậy, nếu bạn đo một truy vấn LINQ là một vấn đề chỉ cần bỏ nó. Nhưng chỉ sau đó.

Đối với mẫu mã của bạn, tôi ước tính sự chậm lại gấp 3 lần. Các phân bổ (và sau đó GC!) ​​Và các indirections thông qua lambdas thực sự bị tổn thương.

+0

Đồng ý. Linq đi kèm với chi phí hiệu suất nhỏ, nhưng trong nhiều trường hợp nó có thể cẩu thả. Thực tế, từ những gì tôi nhớ hầu hết mã đằng sau StackOverflow sử dụng LINQ –

+0

+1 và muốn thêm, chỉ 20% mã chạy 80% thời gian, vì vậy chỉ nên tối ưu hóa tắc nghẽn nếu có sự cố về hiệu suất –

+1

+ 1 lời giải thích tốt 99,9% thẳng ':)' – spajce

2

Vâng, bạn đã tự mình trả lời câu hỏi của mình.

Đi với vòng lặp For nếu bạn muốn có hiệu suất tốt nhất hoặc đi với Linq nếu bạn muốn dễ đọc. Cũng có lẽ hãy ghi nhớ khả năng sử dụng Parallel.Foreach(), nó sẽ được hưởng lợi từ các biểu thức lambda trực tuyến (vì vậy, gần gũi hơn với LINQ), và đó là dễ đọc hơn sau đó làm paralelization "thủ công".

+1

Tôi luôn tự hỏi tại sao biểu thức LINQ và lambda được tự động xem là dễ đọc hơn. Đôi khi, việc đọc hoặc đơn giản dễ đọc hơn LINQ IMO –

+0

@LeeDale tất nhiên. Và tôi muốn thêm câu trả lời của tôi là liên quan đến bố cục phong cách thông thạo của LINQ, giống như trong câu hỏi, không phải là kiểu khai báo. – dutzu

1

Tôi không nghĩ một trong hai được coi là thực hành tốt nhất một số người thích xem LINQ và một số thì không.

Nếu hiệu suất là vấn đề tôi sẽ cấu hình cả hai bit mã cho kịch bản của bạn và nếu sự khác biệt là không đáng kể thì hãy đi với một trong những bạn cảm thấy phù hợp hơn, sau khi tất cả nó sẽ rất có thể là bạn duy trì mã.

Bạn cũng nghĩ về việc sử dụng PLINQ hoặc làm cho vòng lặp chạy song song?

+0

+1 cho PLINQ ': D' – spajce

2

Luôn có tình trạng khó xử giữa hiệu suất và khả năng bảo trì. Và thông thường (nếu không có yêu cầu cụ thể về hiệu suất) khả năng bảo trì sẽ thắng. Chỉ khi bạn có vấn đề về hiệu suất, thì bạn nên ứng dụng hồ sơ, tìm nguồn vấn đề và cải thiện hiệu suất của nó (bằng cách giảm khả năng bảo trì cùng một lúc, có đó là thế giới chúng ta đang sống).

Giới thiệu về mẫu của bạn. LINQ không phải là giải pháp rất tốt ở đây, bởi vì nó không thêm tính bảo trì phù hợp vào mã của bạn. Trên thực tế cho tôi chiếu, lọc, và chiếu một lần nữa trông tồi tệ hơn, hơn vòng lặp đơn giản. Những gì bạn cần ở đây là Array đơn giản.IndexOf, đó là dễ bảo trì hơn, so với vòng lặp, và có gần như cùng một hiệu suất:

Array.IndexOf(array, matchString) 
24

Hơi hiệu suất tốt hơn? Một vòng lặp sẽ mang lại hiệu suất tốt hơn đáng kể!

Hãy xem xét mã bên dưới. Trên hệ thống của tôi để xây dựng RELEASE (không gỡ lỗi), nó cung cấp:

Found via loop at index 999999 in 00:00:00.2782047 
Found via linq at index 999999 in 00:00:02.5864703 
Loop was 9.29700432810805 times faster than linq. 

Mã được cố tình thiết lập sao cho mục được tìm thấy ở bên phải. Nếu nó đã đúng ngay từ đầu, mọi thứ sẽ hoàn toàn khác.

using System; 
using System.Collections.Generic; 
using System.Diagnostics; 
using System.Linq; 

namespace Demo 
{ 
    public static class Program 
    { 
     private static void Main(string[] args) 
     { 
      string[] a = new string[1000000]; 

      for (int i = 0; i < a.Length; ++i) 
      { 
       a[i] = "Won't be found"; 
      } 

      string matchString = "Will be found"; 

      a[a.Length - 1] = "Will be found"; 

      const int COUNT = 100; 

      var sw = Stopwatch.StartNew(); 
      int matchIndex = -1; 

      for (int outer = 0; outer < COUNT; ++outer) 
      { 
       for (int i = 0; i < a.Length; i++) 
       { 
        if (a[i] == matchString) 
        { 
         matchIndex = i; 
         break; 
        } 
       } 
      } 

      sw.Stop(); 
      Console.WriteLine("Found via loop at index " + matchIndex + " in " + sw.Elapsed); 
      double loopTime = sw.Elapsed.TotalSeconds; 

      sw.Restart(); 

      for (int outer = 0; outer < COUNT; ++outer) 
      { 
       matchIndex = a.Select((r, i) => new { value = r, index = i }) 
          .Where(t => t.value == matchString) 
          .Select(s => s.index).First(); 
      } 

      sw.Stop(); 
      Console.WriteLine("Found via linq at index " + matchIndex + " in " + sw.Elapsed); 
      double linqTime = sw.Elapsed.TotalSeconds; 

      Console.WriteLine("Loop was {0} times faster than linq.", linqTime/loopTime); 
     } 
    } 
} 
+4

+1 cho những nỗ lực': D' – spajce

+2

Vấn đề là toán tử mới làm chậm truy vấn LINQ. Nếu mảng có thể được chuyển đổi thành một danh sách hơn linq có thể được kết hợp với FindIndex và lần này vòng lặp for chỉ nhanh hơn khoảng 1,5 lần. 'matchIndex = a.ToList(). FindIndex (x => x.Equals (matchString));' – JohnCambell

+0

thay đổi truy vấn của bạn thành một cái gì đó gần hơn với vòng lặp thông thường, làm giảm sự khác biệt đáng kể: 'string tst = a.First (s => matchIndex ++! = - 2 && s == matchString); ' – jmoreno

3

LINQ, theo mô hình khai báo, thể hiện logic của phép tính mà không mô tả luồng điều khiển của nó. Truy vấn được định hướng mục tiêu, tự định hướng và do đó dễ dàng phân tích và hiểu. Cũng ngắn gọn. Hơn nữa, bằng cách sử dụng LINQ, một phụ thuộc rất cao vào sự trừu tượng của cấu trúc dữ liệu. Điều đó liên quan đến tỷ lệ bảo trì cao và khả năng sử dụng lại.

Iteration aproach đề cập đến mô hình bắt buộc. Nó cung cấp cho kiểm soát hạt mịn, do đó dễ dàng có được hiệu suất cao hơn. Mã cũng đơn giản hơn để gỡ lỗi. Đôi khi việc lặp lại tốt cũng dễ đọc hơn truy vấn.

Các vấn đề liên quan