40

Tôi đang sử dụng Parallel.ForEach và tôi đang làm một số cập nhật cơ sở dữ liệu, bây giờ mà không cần thiết lập MaxDegreeOfParallelism, một bộ xử lý lõi kép kết quả trong thời gian chờ máy khách sql, nơi khác quad core xử lý máy bằng cách nào đó không timeout.MaxDegreeOfParallelism làm gì?

Bây giờ tôi không thể kiểm soát loại lõi bộ xử lý có sẵn khi mã của tôi chạy, nhưng có một số cài đặt tôi có thể thay đổi với MaxDegreeOfParallelism có thể chạy ít hoạt động cùng một lúc hơn và không dẫn đến hết thời gian chờ không?

Tôi có thể tăng thời gian chờ nhưng không phải là giải pháp tốt, nếu trên CPU thấp hơn, tôi có thể xử lý ít hoạt động đồng thời hơn, điều đó sẽ giảm tải trên CPU.

Ok tôi đã đọc tất cả các bài đăng và MSDN khác, nhưng sẽ thiết lập MaxDegreeOfParallelism để giá trị thấp hơn làm cho máy lõi tứ của tôi bị ảnh hưởng?

Ví dụ, có anyway để làm điều gì đó như thế, nếu CPU có hai lõi, sau đó sử dụng 20, nếu CPU có bốn lõi sau đó 40?

Trả lời

58

Câu trả lời là nó là giới hạn trên cho toàn bộ hoạt động song song, không phân biệt số lượng lõi.

Vì vậy, ngay cả khi bạn không sử dụng CPU vì bạn đang chờ IO, hoặc khóa, không có tác vụ bổ sung nào sẽ chạy song song, chỉ tối đa mà bạn chỉ định.

Để tìm hiểu điều này, tôi đã viết đoạn mã thử nghiệm này. Có một khóa nhân tạo trong đó để kích thích TPL sử dụng nhiều chủ đề hơn. Điều tương tự cũng sẽ xảy ra khi mã của bạn đang chờ IO hoặc cơ sở dữ liệu.

class Program 
{ 
    static void Main(string[] args) 
    { 
     var locker = new Object(); 
     int count = 0; 
     Parallel.For 
      (0 
      , 1000 
      , new ParallelOptions { MaxDegreeOfParallelism = 2 } 
      , (i) => 
        { 
         Interlocked.Increment(ref count); 
         lock (locker) 
         { 
          Console.WriteLine("Number of active threads:" + count); 
          Thread.Sleep(10); 
         } 
         Interlocked.Decrement(ref count); 
        } 
      ); 
    } 
} 

Nếu tôi không chỉ định MaxDegreeOfParallelism, ghi nhật ký bảng điều khiển cho thấy tối đa 8 tác vụ đang chạy cùng một lúc. Như thế này:

Number of active threads:6 
Number of active threads:7 
Number of active threads:7 
Number of active threads:7 
Number of active threads:7 
Number of active threads:7 
Number of active threads:6 
Number of active threads:7 
Number of active threads:7 
Number of active threads:7 
Number of active threads:7 
Number of active threads:7 
Number of active threads:7 
Number of active threads:7 
Number of active threads:7 
Number of active threads:7 
Number of active threads:7 
Number of active threads:7 
Number of active threads:7 

Nó bắt đầu thấp hơn, tăng theo thời gian và cuối cùng nó cố gắng chạy 8 cùng một lúc.

Nếu tôi hạn chế nó đến một số giá trị tùy ý (ví dụ 2), tôi nhận được

Number of active threads:2 
Number of active threads:1 
Number of active threads:2 
Number of active threads:2 
Number of active threads:2 
Number of active threads:2 
Number of active threads:2 
Number of active threads:2 
Number of active threads:2 
Number of active threads:2 
Number of active threads:2 
Number of active threads:2 
Number of active threads:2 
Number of active threads:2 
Number of active threads:2 
Number of active threads:2 
Number of active threads:2 

Oh, và điều này là trên một máy quadcore.

+0

Logic của tôi không có bất kỳ chờ đợi hoặc bất kỳ IO, nó chỉ cập nhật SQL, có SQL có thể có riêng của mình, nhưng chủ yếu là tôi đang chờ đợi SQL để kết thúc. Tối đa mặc định không có chủ đề đang hoạt động được sử dụng là gì? –

+0

Giá trị mặc định là 2 cho mỗi lõi, nhưng TPL có thể tăng giá trị này nếu mã của bạn không sử dụng CPU. Hầu hết các cơ sở dữ liệu liên quan đến một số lượng IO. –

+1

Nếu máy 6 lõi của tôi bị tải nặng, nó chỉ sử dụng 1 hoặc 2 luồng. Nếu nó được nạp nhẹ, nó sẽ lên tới 12. Nó đủ thông minh để tính tải hệ thống hiện có. – Contango

-1

nó đặt số chủ đề để chạy song song ...

+0

Nhưng liệu có cần tính đến lõi không? –

+0

về cơ bản loại db bạn đang sử dụng? – SolidSnake

+0

Cùng một hệ điều hành, cùng một chương trình, cùng một dữ liệu (Replicators bascially), nhưng một là một máy cao cấp với lõi tứ kép, và hai là máy lõi kép đơn giản, cùng một chương trình lấy dữ liệu từ các máy chủ khác và lưu trữ dữ liệu trở lại SQL (rất nhiều blobs và hình ảnh). –

1

Có vẻ như mã mà bạn đang chạy song song được deadlocking, điều đó có nghĩa rằng trừ khi bạn có thể tìm và sửa chữa các vấn đề mà gây ra rằng, bạn không nên song song nó chút nào.

+0

-1, Câu hỏi không phải là về song song hay không song song, đơn giản của nó là SQL thực hiện các phép tính riêng của nó nhưng quá nhiều yêu cầu song song làm cho thời gian chờ của khách hàng, tôi muốn chạy các hoạt động ít hơn. Deadlock không phải là một vấn đề như máy lõi tứ với cùng một logic, cùng một SQL chạy tốt, tôi không muốn tiếp tục tăng thời gian chờ. –

+0

Bạn đã thử tăng thời gian chờ và xác nhận rằng nó hoạt động? Các vấn đề tương tranh có thể cực kỳ tinh tế và nhiều thứ có thể khiến chúng biến mất và xuất hiện lại dường như ngẫu nhiên. Thực tế là nó hoạt động trên một cỗ máy khác với nhiều lõi hơn không có nghĩa là nó không bị hỏng, hoặc nhiều lõi hơn là thứ đã giúp. – jimrandomh

+0

Tăng thời gian chờ sẽ giúp ích. Nhưng bằng cách nào đó việc sử dụng CPU trên 50% trên các máy nhỏ và trên các máy lớn ít hơn 5%, bây giờ tôi đang ở thời điểm tôi cần tìm ra vấn đề hiệu suất và có điều gì đó tôi có thể làm để thay đổi mã hoặc chỉ cần để nâng cấp CPU. –

13

Ví dụ, có cách nào để làm điều gì đó giống như, nếu CPU có hai lõi, sau đó sử dụng 20, nếu CPU có bốn lõi thì 40?

Bạn có thể làm điều này để làm song song phụ thuộc vào số lượng các lõi CPU:

var options = new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount * 10 }; 
Parallel.ForEach(sourceCollection, options, sourceItem => 
{ 
    // do something 
}); 

Tuy nhiên, mới hơn CPU của xu hướng sử dụng Hyper-Threading để mô phỏng lõi thêm. Vì vậy, nếu bạn có bộ xử lý lõi tứ, thì Environment.ProcessorCount có thể sẽ báo cáo điều này là 8 lõi. Tôi đã tìm thấy rằng nếu bạn thiết lập song song để tính toán cho các lõi mô phỏng thì nó thực sự làm chậm các chủ đề khác như các luồng giao diện người dùng.

Vì vậy, mặc dù hoạt động sẽ kết thúc nhanh hơn một chút, một giao diện người dùng ứng dụng có thể gặp phải tình trạng trễ đáng kể trong thời gian này. Chia 'Environment.ProcessorCount' cho 2 dường như đạt được tốc độ xử lý giống nhau trong khi vẫn giữ CPU sẵn sàng cho các chủ đề giao diện người dùng.