2013-02-04 17 views
5

Một trong những điều tốt đẹp về LINQ là có nguồn dữ liệu vô hạn được xử lý một cách lười biếng theo yêu cầu. Tôi đã thử song song các truy vấn của mình và thấy rằng tải chậm không hoạt động. Ví dụ:Làm cách nào để tải nội dung tải xuống với PLINQ?

class Program 
{ 
    static void Main(string[] args) 
    { 
     var source = Generator(); 
     var next = source.AsParallel().Select(i => ExpensiveCall(i)); 
     foreach (var i in next) 
     { 
      System.Console.WriteLine(i); 
     } 
    } 

    public static IEnumerable<int> Generator() 
    { 
     int i = 0; 
     while (true) 
     { 
      yield return i; 
      i++; 
     } 
    } 

    public static int ExpensiveCall(int arg) 
    { 
     System.Threading.Thread.Sleep(5000); 
     return arg*arg; 
    } 
} 

Chương trình này không tạo ra bất kỳ kết quả nào, có lẽ vì ở mỗi bước, chờ tất cả các cuộc gọi đến máy phát điện sẽ không bao giờ. Nếu tôi đưa ra cuộc gọi "AsParallel", nó hoạt động tốt. Vì vậy, làm thế nào để tôi có được tải lười biếng tốt đẹp của tôi trong khi sử dụng PLINQ để cải thiện hiệu suất của các ứng dụng của tôi?

Trả lời

5

Hãy xem MergeOptions

var next = source.AsParallel() 
       .WithMergeOptions(ParallelMergeOptions.NotBuffered) 
       .Select(i => ExpensiveCall(i)); 
2

Tôi nghĩ bạn đang nhầm lẫn hai thứ khác nhau. Vấn đề ở đây không phải là tải chậm (tức là chỉ tải nhiều nhất là cần thiết), vấn đề ở đây là đệm đầu ra (tức là không trả lại kết quả ngay lập tức).

Trong trường hợp của bạn, bạn sẽ nhận được kết quả cuối cùng, mặc dù nó có thể mất một thời gian (đối với tôi, nó yêu cầu một cái gì đó giống như 500 kết quả cho nó để trả lại đợt đầu tiên). Việc đệm được thực hiện vì lý do hiệu suất, nhưng trong trường hợp của bạn, điều đó không có ý nghĩa. Như Ian đã chỉ ra một cách chính xác, bạn nên sử dụng .WithMergeOptions(ParallelMergeOptions.NotBuffered) để tắt đệm đầu ra.

Nhưng, theo như tôi biết, PLINQ không làm tải chậm và không có cách nào để thay đổi điều đó. Điều đó có nghĩa là nếu người tiêu dùng của bạn (trong trường hợp của bạn, vòng lặp foreach) quá chậm, PLINQ sẽ tạo kết quả nhanh hơn mức cần thiết và nó sẽ chỉ dừng lại khi bạn kết thúc lặp lại kết quả. Điều này có nghĩa PLINQ có thể lãng phí thời gian và bộ nhớ CPU.

+0

điểm rất tốt ... bộ đệm trong PLINQ chỉ che giấu các vấn đề không tải chậm. Có lẽ một cách để đi là có một phương pháp mở rộng mà lô các mục tiếp theo n, và thực hiện những người song song, sau đó mang lại kết quả trở lại. Điều đó có thể tạo ra hành vi giả lười biếng ... – tbischel

+0

@tbischel Vâng, một cái gì đó như thế sẽ hoạt động. Một tùy chọn khác là sử dụng 'BlockingCollection' với tập hợp' BoundedCapacity'. – svick

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