2012-06-06 30 views
5

Tôi đã viết một số mã mẫu cơ bản để tự làm quen với PLINQ.Tại sao truy vấn PLINQ AsOrdered của tôi lại nhanh hơn số

Tôi đã gặp phải điều gì đó kỳ lạ. Tôi không biết nếu đó là một lỗi trong mã của tôi hoặc một lỗi trong sự hiểu biết của tôi về PLINQ.

Tài liệu MSDN nói rằng việc thêm AsOrdered() sẽ duy trì thứ tự cuộc gọi với chi phí hiệu suất có thể.

Tôi đã viết một số kiểm tra đơn vị và nhận thấy hiệu ứng trên đơn đặt hàng trên tập kết quả như đã nêu trong tài liệu. Nhưng tôi đã thấy hiệu ứng nghịch đảo về hiệu suất.

Dưới đây là cả hai phương pháp của tôi:

public IEnumerable<int> ParallelCalculatePrimesUpTo(int maxValue) 
{ 
    return from number in Enumerable.Range(1, maxValue).AsParallel() 
      where IsPrime(number) 
      select number; 
} 

public IEnumerable<int> OrderedParallelCalculatePrimesUpTo(int maxValue) 
{ 
    return from number in Enumerable.Range(1, maxValue).AsParallel().AsOrdered() 
      where IsPrime(number) 
      select number; 
} 

Và tiêu chuẩn rất đơn giản của tôi

[TestMethod] 
    public void SimplisticBenchmark6() 
    { 
     var primeNumberCalculator = new PrimeNumberCalculator(); 

     var startTime = DateTime.Now; 

     primeNumberCalculator.ParallelCalculatePrimesUpTo(10000000).ToList(); 

     var totalTime = DateTime.Now - startTime; 

     Console.WriteLine(totalTime); 
    } 

    [TestMethod] 
    public void SimplisticBenchmark7() 
    { 
     var primeNumberCalculator = new PrimeNumberCalculator(); 

     var startTime = DateTime.Now; 

     primeNumberCalculator.OrderedParallelCalculatePrimesUpTo(10000000).ToList(); 

     var totalTime = DateTime.Now - startTime; 

     Console.WriteLine(totalTime); 
    } 

Không có vấn đề bao lâu thì tôi chạy thử nghiệm này, các phiên bản ra lệnh nhịp đập ra một thứ tự. Tôi nhận được khoảng 4 giây nhanh hơn cho một thứ tự trên máy tính lõi tứ của tôi. Tôi nhận được khoảng 18 giây cho một thứ tự và 22 giây cho người không có thứ tự. Tôi đã chạy thử nghiệm hàng chục lần trong thời gian hai ngày (với khởi động lại giữa những ngày đó).

Nếu tôi hạ thấp số từ 10 000 000 xuống 6 000 000, sự khác biệt vẫn còn ở đó nhưng ít đáng chú ý hơn và nếu tôi hạ thấp xuống còn 3 000 000, nó sẽ có cùng tốc độ.

Tôi đã thử chạy thử nghiệm theo cả hai thứ tự thực thi và kết quả giống nhau.

Dưới đây là phương pháp isPrime đó được gọi là trong truy vấn PLINQ:

// uses inneficient trial division algorithm 
private bool IsPrime(int number) 
{ 
    if (number == 1) 
     return false; 

    for (int divisor = 2; divisor <= Math.Sqrt(number); divisor++) 
    { 
     if (number % divisor == 0) 
      return false; 
    } 

    return true; 
} 

Điều này giải thích?

+5

Như một lưu ý phụ, 'DateTime' không phải là rất tốt cho phép đo hiệu suất, sử dụng' StopWatch' là tốt hơn. – svick

+0

@svick: Rất tốt. Tôi biết DateTime không tốt cho các phép đo nghiêm trọng nhưng không biết về StopWatch. Cảm ơn. Đối với mã sản xuất nó tốt hơn để sử dụng một hồ sơ, nhưng điều này chỉ là mã nhanh chóng và bẩn tôi đã viết khi tôi đọc PLINQ và TPL doc. Lần tới tôi sẽ sử dụng StopWatch trong tình huống như vậy! – Gilles

+0

Nếu tôi chạy mã của bạn, đặt hàng hơi chậm hơn (5,67 s so với 5,66 s cho không có thứ tự, trung bình trong một số lần thử), nhưng chênh lệch giữa các lần thử cao hơn sự khác biệt giữa thứ tự và không có thứ tự, vì vậy tôi nghĩ rằng không có sự khác biệt có ý nghĩa thống kê trong trường hợp này (ít nhất là được đo trên lõi tứ của tôi). – svick

Trả lời

1

Bạn có thể cho chúng tôi biết mức độ sử dụng CPU trên 4 lõi khác nhau không? Có thể AsOrdered() đang buộc các cuộc gọi tuần tự hơn xảy ra trên cùng một lõi. Với địa phương được cải thiện, bộ nhớ đệm ở mức độ silicon và dự đoán nhánh có thể làm việc có lợi cho bạn.

Một khả năng khác là có một số tối ưu hóa trong khuôn khổ .NET cho trường hợp các số nguyên tăng dần đơn điệu (int.Range) khi sử dụng phép chiếu AsOrdered(). Tôi không chắc nó sẽ hoạt động như thế nào, nhưng có thể.

Một thử nghiệm thú vị để so sánh sẽ là tạo một tập hợp số thứ ba, theo thứ tự ngẫu nhiên (rõ ràng, bạn phải ngẫu nhiên chúng trước và sau đó làm việc ba mảng). Sau đó, xem nếu có bất cứ điều gì để làm với nó?

+0

Tôi nhận được khá nhiều điều tương tự cho cả hai, ở đây: http://gillesleblanc.wordpress.com/?attachment_id=361 là một hình ảnh từ Windows Task Manager. Đây là bốn lõi. Bốn tăng khoảng 100% cho cả hai thử nghiệm. Bài kiểm tra đầu tiên là lần tăng đầu tiên, và bài kiểm tra thứ hai là lần tăng thứ hai. – Gilles

+0

Được rồi - Tôi biết có một số công cụ ưa thích từ Intel, AMD và các công cụ khác cho phép bạn theo dõi bộ nhớ đệm, v.v. nhưng tôi không chắc chắn về chi tiết. Tùy chọn đơn giản: Tôi chỉ nhận thấy rằng hai thử nghiệm đang chạy trong các phương thức [TestMethod] riêng biệt. Bạn có thể kết hợp chúng thành một [TestMethod] duy nhất - có thể là một phương pháp cho mỗi đơn đặt hàng - và so sánh hiệu quả của việc đặt hàng theo cách đó? Sau đó, bạn đã loại trừ một số yếu tố môi trường MSTest. (Trong thực tế, đi tất cả các cách và viết này như là một ứng dụng giao diện điều khiển độc lập. Tôi nghĩ rằng MSTest có một cơ sở trong đó kiểm tra các bài kiểm tra bị đình trệ/treo.) –

+0

Tôi đã viết một ứng dụng giao diện điều khiển gọi cả hai phương pháp 4 lần thứ tự sau đây: không có thứ tự , ra lệnh, ra lệnh, không theo thứ tự, không sắp xếp, ra lệnh, ra lệnh, không có thứ tự. Ngoại trừ các cuộc gọi đầu tiên mà là chậm hơn tất cả các cuộc gọi tiếp theo rơi gần kết quả của tôi trong các bài kiểm tra đơn vị của tôi. – Gilles

3

Bạn có luôn chạy thử nghiệm theo thứ tự giống nhau không?

Tôi đã tạo lại kết quả của bạn trên máy tính của mình và tôi thấy rằng, bất kể kết quả 'Đặt hàng' nhanh hơn. Tôi đã sử dụng mã được sửa đổi một chút cho điểm chuẩn:

static void Main(string[] args) 
{ 
    const int size = 9000000; 
    BenchIt("Parallel", ParallelCalculatePrimesUpTo, size); 
    BenchIt("Ordered ", OrderedParallelCalculatePrimesUpTo, size); 
    Console.ReadKey(); 
} 

public static void BenchIt(string desc, Func<int, IEnumerable<int>> myFunc, int size) 
{ 
    var sw = new Stopwatch();    
    sw.Restart(); 
    myFunc.Invoke(size).ToList(); 
    sw.Stop(); 
    Console.WriteLine("{0} {1}",desc, sw.Elapsed); 
} 

Kết quả của tôi cho thấy, ban đầu, bạn đã chính xác. Phương thức đặt hàng nhanh hơn. Tuy nhiên, nếu tôi THAY ĐỔI thứ tự của các cuộc gọi, tôi thấy rằng phương pháp không được đặt hàng nhanh hơn. Nói cách khác, bất cứ ai đi thứ hai đều nhanh hơn. Có lẽ, vì quản lý luồng-chủ đề mà Thư viện song song nhiệm vụ đang thực hiện.

Nhưng - sự khác biệt giữa hai máy trên máy của tôi rất nhỏ. Không nơi nào gần số lượng chênh lệch bạn thấy.

Phần cứng của bạn trông như thế nào?

PLINQ thực hiện một số phỏng đoán về cách thực hiện nhanh nhất. Tôi không biết nếu điều này sẽ trực tiếp giúp bạn trong trường hợp này; nhưng bạn có thể muốn đặt điểm ngắt ở giữa IsPrime và dừng lại sau vài trăm lần lặp lại và kiểm tra cửa sổ luồng.

Bạn có bao nhiêu chủ đề khi thực hiện ParallelCalculatedPrimesUpTo câu OrderedParallelCalculatePrimesUpTo? Tôi đang đến đây; nhưng có thể nó quyết định các giá trị khác nhau trên máy của bạn, tạo ra những thời điểm bất ngờ mà bạn đang thấy. Trên máy của tôi - tôi nhận được tám chủ đề, mỗi lần - nhưng thời gian của tôi là giống hệt nhau - bất kỳ cái nào được gọi là đầu tiên đều chậm hơn do việc tạo các chuỗi đó. Nhưng bạn không được đảm bảo một số chủ đề cụ thể (bạn có thể đặt số lượng tối đa, nhưng bạn không thể buộc chúng được sử dụng).

+0

Về câu hỏi đầu tiên, tôi nhận được cùng một mẫu trong kết quả nếu tôi chạy chúng theo thứ tự bất kỳ hoặc nếu tôi chạy chúng riêng rẽ trong các thử nghiệm khác nhau chạy. – Gilles

+0

Về câu hỏi thứ hai (phần cứng): AMD Phenom 9550 Quad-Core Process 2,20 Ghz, 6,00 GB RAM, 64 bit OS/cpu, thẻ NVIDIA gfx (1GB VRAM), 7200 rpm HDD. – Gilles

+0

Kiểm tra không có thứ tự hiển thị tổng cộng 14 luồng trong cửa sổ, nhưng 2 dường như là từ tác nhân thử nghiệm. Lệnh thứ tự hiển thị 16 luồng, nhưng một lần nữa chỉ có 2 từ tác nhân thử nghiệm. Trong cả hai trường hợp, nhiều chủ đề dường như không liên quan đến chương trình của tôi hoặc tên không mô tả (cho đôi mắt của tôi). – Gilles

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