2009-11-28 25 views
7

Giả sử tôi có một nhiệm vụ bị ràng buộc bởi IO. Tôi đang sử dụng WithDegreeOfParallelism = 10 và WithExecution = chế độ ForceParallelism, nhưng vẫn truy vấn chỉ sử dụng hai chủ đề. Tại sao?Tại sao PLINQ chỉ sử dụng hai luồng?

Tôi hiểu PLINQ thường sẽ chọn một mức độ song song tương đương với số lõi của tôi, nhưng tại sao nó bỏ qua yêu cầu cụ thể của tôi về tính song song cao hơn?

static void Main(string[] args) 
{ 
    TestParallel(0.UpTo(8)); 
} 

private static void TestParallel(IEnumerable<int> input) 
{ 
    var timer = new Stopwatch(); 
    timer.Start(); 
    var size = input.Count(); 

    if (input.AsParallel(). 
     WithDegreeOfParallelism(10). 
     WithExecutionMode(ParallelExecutionMode.ForceParallelism). 
     Where(IsOdd).Count() != size/2) 
     throw new Exception("Failed to count the odds"); 

    timer.Stop(); 
    Console.WriteLine("Tested " + size + " numbers in " + timer.Elapsed.TotalSeconds + " seconds"); 
} 

private static bool IsOdd(int n) 
{ 
    Thread.Sleep(1000); 
    return n%2 == 1; 
} 
+2

Bạn có bao nhiêu bộ xử lý/lõi? – LukeH

+2

Hai. Nhưng tôi đã nói cụ thể mức độ song song là 10. – ripper234

+0

Nếu bạn có một nhiệm vụ bị ràng buộc I/O và chạy nó trên nhiều luồng song song, cải thiện tốc độ thì có lẽ nó không thực sự là I/O bị ràng buộc ngay từ đầu, chỉ được viết kém (ví dụ: đồng bộ hóa thay vì không đồng bộ). –

Trả lời

8

PLINQ cố gắng tìm số chuỗi tối ưu để thực hiện những gì bạn muốn làm nhanh nhất có thể, nếu bạn chỉ có 2 lõi trên cpu của bạn, con số đó rất có thể là 2. Nếu bạn có lõi tứ, bạn sẽ có nhiều khả năng nhìn thấy 4 chủ đề xuất hiện, nhưng việc tạo 4 luồng trên một máy lõi kép sẽ không thực sự cải thiện hiệu suất bởi vì chỉ có 2 luồng có thể hoạt động cùng một lúc.

Ngoài ra, với các thao tác dựa trên IO, có khả năng là bất kỳ chuỗi bổ sung nào cũng sẽ chặn hoạt động IO đầu tiên được thực hiện.

+4

Không thực sự trả lời câu hỏi của tôi - tại sao nó lại chọn sử dụng hai luồng mặc dù tôi đặc biệt yêu cầu mức độ song song = 10? (Cập nhật câu hỏi) – ripper234

+3

@ ripper234: Từ tài liệu MSDN: "Mức độ song song là ** số lượng tối đa ** đồng thời thực hiện các tác vụ sẽ được sử dụng để xử lý truy vấn". 'WithDegreeOfParallelism' chỉ là một gợi ý rằng PLINQ nên sử dụng * không nhiều hơn * hơn * n * luồng. http://msdn.microsoft.com/en-us/library/dd383719%28VS.100%29.aspx – LukeH

+3

Vậy ... không có cách nào để sử dụng hiệu quả PLINQ cho các tác vụ bị ràng buộc bởi IO? – ripper234

4

10 là tối đa

Thiết lập mức độ song song để sử dụng trong một truy vấn. Mức độ song song là số lượng tối đa đồng thời các tác vụ thực thi sẽ được sử dụng để xử lý truy vấn.

Từ đây:

MSDN

+0

Theo mặc định, PLINQ sử dụng tất cả các bộ vi xử lý trên máy chủ lưu trữ tối đa ** 64 **. Bạn có thể hướng dẫn PLINQ sử dụng không quá một số bộ vi xử lý được chỉ định bằng cách sử dụng phương thức WithDegreeOfParallelism (Of TSource). http://msdn.microsoft.com/en-us/library/dd383719.aspx –

2

Có vẻ PLINQ chỉnh số lượng các chủ đề. Khi tôi quấn mã ở trên trong một vòng lặp while (true), hai lần lặp đầu tiên mất hai giây để chạy, nhưng lần thứ ba trở lên chỉ mất một giây. PLINQ hiểu các lõi đang nhàn rỗi và tăng số lượng các luồng. Ấn tượng!

+1

Lưu ý rằng để điều này xảy ra, bạn thực sự phải chỉ định WithDegreeOfParallelism, nếu không PLINQ sẽ tự giới hạn số lượng lõi trên máy của bạn. – ripper234

0

Tôi đồng ý với Rory, ngoại trừ IO. Chưa được thử nghiệm với đĩa IO, nhưng mạng IO dứt khoát có thể hiệu quả hơn với nhiều luồng hơn là có lõi trên CPU.

thử nghiệm đơn giản (nó sẽ là đúng hơn để chạy thử nghiệm với mỗi thread đếm nhiều lần, như tốc độ mạng không phải là không đổi, nhưng vẫn còn) để chứng minh rằng:

[Test] 
    public void TestDownloadThreadsImpactToSpeed() 
    { 
     var sampleImages = Enumerable.Range(0, 100) 
      .Select(x => "url to some quite large file from good server which does not have anti DSS stuff.") 
      .ToArray();    

     for (int i = 0; i < 8; i++) 
     { 
      var start = DateTime.Now; 
      var threadCount = (int)Math.Pow(2, i); 
      Parallel.For(0, sampleImages.Length - 1, new ParallelOptions {MaxDegreeOfParallelism = threadCount}, 
         index => 
          { 
           using (var webClient = new WebClient()) 
           { 
            webClient.DownloadFile(sampleImages[index], 
                  string.Format(@"c:\test\{0}", index)); 
           } 
          }); 

      Console.WriteLine("Number of threads: {0}, Seconds: {1}", threadCount, (DateTime.Now - start).TotalSeconds); 
     } 
    } 

quả với hình ảnh 500x500px từ CDN sử dụng máy 8 lõi với SSD là:

số chủ đề: 1, Giây: 25,3904522
số bài: 2, Giây: 10,8986233
số bài: 4, Giây: 9,9325681
Số bài: 8, Giây: 3,7352137
Số chủ đề: 16 Giây: 3,3071892
Số chủ đề: 32, Giây: 3,1421797
Số chủ đề: 64, Giây: 3,1161782
Số chủ đề: 128, Giây: 3,7272132

kết quả cuối đã lần như vậy tôi nghĩ rằng trước hết bởi vì chúng ta phải tải về chỉ có 100 hình ảnh :)

thời gian chênh lệch sử dụng 8-64 đề không phải là lớn, nhưng đó là trên 8 lõi máy.Nếu nó là 2 lõi máy (máy tính xách tay enduser giá rẻ), tôi nghĩ rằng buộc phải sử dụng 8 chủ đề sẽ có tác động nhiều hơn, hơn trên 8 lõi máy buộc phải sử dụng 64 chủ đề.

+0

Bạn đã tính trung bình các con số này, ví dụ, 10.000 lần lặp lại? – ChrisF

+0

Tôi đã đề cập, rằng sẽ chính xác hơn khi chạy thử nghiệm với mỗi chuỗi đếm nhiều lần. Dù sao, điểm là để buộc các chủ đề hơn cho máy móc, có số lượng cpu thấp, trong trường hợp bạn đang làm IO mạng. – Giedrius

+0

Dường như các tùy chọn song song đang bị bỏ qua cho> = 8. Thêm một số đầu ra gỡ lỗi trong cơ thể song song và tôi tin rằng bạn sẽ thấy rằng chỉ có tối đa là 8 tại một thời điểm đang chạy và nó được điều chỉnh. – crokusek

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