2013-05-08 42 views
6

Tôi có một chương trình đơn giản thực hiện một số thuật toán Monte Carlo. Một lần lặp với thuật toán là không có tác dụng phụ, vì vậy tôi có thể chạy nó với nhiều luồng. Vì vậy, đây là phần có liên quan của my whole program, được viết bằng C++ 11:Chương trình chậm hơn khi sử dụng nhiều chủ đề

void task(unsigned int max_iter, std::vector<unsigned int> *results, std::vector<unsigned int>::iterator iterator) { 
    for (unsigned int n = 0; n < max_iter; ++n) { 
     nume::Album album(535); 
     unsigned int steps = album.fill_up(); 
     *iterator = steps; 
     ++iterator; 
    } 
} 

void aufgabe2() { 
    std::cout << "\nAufgabe 2\n"; 

    unsigned int max_iter = 10000; 

    unsigned int thread_count = 4; 

    std::vector<std::thread> threads(thread_count); 
    std::vector<unsigned int> results(max_iter); 

    std::cout << "Computing with " << thread_count << " threads" << std::endl; 

    int i = 0; 
    for (std::thread &thread: threads) { 
     std::vector<unsigned int>::iterator start = results.begin() + max_iter/thread_count * i; 
     thread = std::thread(task, max_iter/thread_count, &results, start); 
     i++; 
    } 

    for (std::thread &thread: threads) { 
     thread.join(); 
    } 

    std::ofstream out; 
    out.open("out-2a.csv"); 
    for (unsigned int count: results) { 
     out << count << std::endl; 
    } 
    out.close(); 

    std::cout << "Siehe Plot" << std::endl; 
} 

Điều khó hiểu là nó chậm hơn các chủ đề tôi thêm vào. Với 4 chủ đề, tôi có được điều này:

real 0m5.691s 
user 0m3.784s 
sys  0m10.844s 

Trong khi đó với một chủ đề duy nhất:

real 0m1.145s 
user 0m0.816s 
sys  0m0.320s 

Tôi nhận ra rằng việc chuyển dữ liệu giữa các lõi CPU có thể thêm chi phí, nhưng vector cần được khai báo lúc khởi động, và không được sửa đổi ở giữa. Có bất kỳ lý do cụ thể cho việc này để được chậm hơn trên nhiều lõi?

hệ thống của tôi là một i5-2550M, trong đó có 4 lõi (2 + Siêu phân luồng) và tôi sử dụng g ++ (Ubuntu/Linaro 4.7.3-1ubuntu1) 4.7.3

Cập nhật

tôi thấy rằng không sử dụng chủ đề (1), nó sẽ có rất nhiều người sử dụng tải, trong khi với chủ đề (2), nó sẽ có kernel hơn người dùng tải:

10K Chạy:

http://wstaw.org/m/2013/05/08/stats3.png

100K Chạy:

http://wstaw.org/m/2013/05/08/Auswahl_001.png

Current main.cpp

Với 100K chạy, tôi nhận được như sau:

Không đề ở tất cả:

real 0m28.705s 
user 0m28.468s 
sys  0m0.112s 

Một chủ đề cho từng phần của chương trình. Những bộ phận đó thậm chí không sử dụng cùng một bộ nhớ, vì vậy tôi đồng thời cho cùng một container nên được ra là tốt. Nhưng phải mất nhiều thời gian hơn:

real 2m50.609s 
user 2m45.664s 
sys  4m35.772s 

Vì vậy, mặc dù ba phần chính chiếm 300% CPU của tôi, chúng mất gấp 6 lần.

Với thời gian chạy 1M, phải mất real 4m45 để thực hiện. Tôi đã chạy trước đây 1 triệu và phải mất ít nhất real 20m, nếu không ngay cả real 30m.

+1

'10000' thực sự nhỏ ... hãy thử số lớn hơn. – UmNyobe

+2

Có lẽ bối cảnh trên đầu chuyển đổi là thống trị thời gian cần thiết để thực hiện nhiệm vụ ở đây. Như được đề xuất, hãy thêm một vài số không vào đó '10000' ... –

+1

Tạo một chuỗi cũng có phí trên. Cho phép tác vụ thực hiện một 'return' đơn giản và xem số lượng các số đó là tính toán thực tế như thế nào. Ngoài ra cố gắng không tạo chủ đề nào cả (chỉ cần chạy hàm tác vụ từ hiện tại), nó sẽ nhanh hơn. 10K lặp đi lặp lại có lẽ không có gì so với những gì hệ điều hành đã làm để khởi động một chủ đề. – hamstergene

Trả lời

5

Đã đánh giá main.cpp hiện tại của bạn tại GitHub. Ngoài các nhận xét được cung cấp ở trên:

  1. Có, rand() không an toàn để có thể điền trước một số giá trị ngẫu nhiên trước khi chạy logic nghiệp vụ đa luồng của bạn (theo cách đó, bạn giảm số lượng khóa có thể). Giống nhau về cấp phát bộ nhớ nếu bạn có kế hoạch thực hiện một số hoạt động heap (thực hiện trước khi phân bổ trước khi đa luồng hoặc sử dụng tùy chỉnh mỗi thread cấp phát).
  2. Đừng quên các quy trình khác. Nếu bạn dự định sử dụng 4 luồng trên 4 lõi, điều đó có nghĩa là bạn sẽ cạnh tranh với các phần mềm khác (ít nhất là các thói quen hệ điều hành) cho tài nguyên CPU.
  3. Đầu ra tệp là trình phát locker lớn. Bạn làm "< <" nhà điều hành trên mỗi vòng lặp và nó chi phí bạn rất nhiều (tôi nhớ một trường hợp vui trong quá khứ của tôi: làm một log ouput cố định một lỗi đa luồng, gián tiếp. Bởi vì logger chung là khóa-driven, nó là một số loại đồng bộ nguyên thủy, hãy lưu ý!).
  4. Cuối cùng, không có bất kỳ loại bảo hành nào mà ứng dụng đa luồng có thể nhanh hơn chỉ một luồng. Có một loạt các khía cạnh cụ thể cho CPU, môi trường cụ thể, vv.
1

Kết quả đối tượng vectơ được chia sẻ bởi tất cả các chủ đề được tạo, vì vậy ngay cả khi vấn đề của bạn là một điều khó hiểu, do đối tượng được chia sẻ, có tranh cãi chưa kể đến bộ nhớ cache bị bỏ sót (Tôi không đủ tốt để giải thích về lưu trữ trên các kiến ​​trúc hiện đại). có lẽ bạn nên có n kết quả vectơ cho n chủ đề của bạn và cuối cùng kết hợp kết quả. Điều đó sẽ tăng tốc độ, tôi đoán vậy.

Một mẹo khác cần đề cập là sử dụng std :: async bất cứ khi nào có thể thay vì chỉ chuỗi. Nó xử lý phân bổ thread và các messes mức thấp khác. Tôi đọc nó từ cuốn sách C++ 11 hiệu quả của Scott Mayer. Tuy nhiên, bằng cách sử dụng các chủ đề, bạn có thể thiết lập chủ đề mối quan hệ với lõi cụ thể. Vì vậy, nếu bộ vi xử lý của bạn hỗ trợ 8 luồng, bạn có thể tạo 8 luồng và gán mỗi luồng cho mỗi lõi ít ​​nhất là trên Linux.

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