Cài dat thuan toán song song trong dev c++ năm 2024
Trước khi tìm hiểu thế nào là lập trình song song cũng như cách code thì mình phải biết 1 chút về lịch sử hình thành nên ở bài 1 mình sẽ giới thiệu sơ lược những điều bạn nên biết ở lĩnh vực này. 1 lưu ý nhỏ là nếu bạn nào muốn đọc bằng tiếng anh thì có thể ghé qua github, vì tiếng anh nên từ ngữ dùng sẽ chính xác hơn khi viết lại bằng tiếng việt Những điều bạn nên biết về CPU-GPU Chắc chắn ở đây phần lớn các bạn đều quen thuộc với 2 từ CPU và GPU, nhưng sẽ có 1 số ít thì không, nên mình sẽ đi nhanh qua 2 khái niệm này và lịch sử của chúng. CPU là gì?CPU(Central Processing Units) là bộ xử lý trung tâm của máy tính hay có thể nói là "não bộ" của máy tính. Và bộ não này có thể thực hiện các phép tính liên quan đến số học, đo lường, so sánh, logic, đồng thời nhập hoặc xuất dữ liệu từ các mã lệnh trên máy tính. Làm thế nào để đánh giá đó 1 là con CPU chất lượng? chúng ta phần lớn sẽ dựa vào 2 thông số:
Sự phát triển và các trở ngạibiểu đồ mô tả sự biến đổi tần số CPU theo thời gian biểu đồ mô tả sự biến đổi công suất CPU theo thời gian Qua 2 biểu đồ ta có thể thấy sự phát triển nhanh chóng của CPU qua từng giai đoạn nhưng vào giữa năm 2004-2005 đã có sự thụt lùi vậy thì nguyên nhân là gì? Hai vấn đề chính mà CPU đối mặt vào thời điểm đó là "Power wall" và "Memory wall".
Và từ đó thời kì song song bắt đầu diễn ra với ý tưởng đầu tiên là dual core và càng về sau ta có khái niệm GPU GPU là gì?GPU (Graphics Processing Unit) là các thành phần phần cứng chuyên biệt được thiết kế để tăng tốc xử lý đồ họa và các nhiệm vụ tính toán song song. Ban đầu, chúng được phát triển để sử dụng trong các trò chơi máy tính và ứng dụng đồ họa, nhưng hiện nay chúng cũng được sử dụng rộng rãi trong các ứng dụng khoa học và kỹ thuật. Những biểu đồ này minh họa rõ ràng sự tính toán nhanh hơn của GPU so với CPU. Parallel processingparallel processing tức là xử lý song song vậy thì ở đây chúng ta song song điều gì? Giả sử một giáo viên giao cho một lớp học 10 câu hỏi để trả lời. Giải pháp đơn giản nhất là để học sinh giỏi nhất trong lớp hoàn thành tất cả 10 câu hỏi. Tuy nhiên, nếu chúng ta có thể tìm và đào tạo 9 học sinh còn lại để trở nên giỏi như học sinh giỏi nhất, chúng ta có thể tăng tốc quá trình trả lời câu hỏi lên 10 lần và đó chính là cách GPU hoạt động. Tóm lại, việc tiết kiệm thời gian bằng cách chia nhỏ nhiệm vụ lớn thành những nhiệm vụ nhỏ hơn có thể được xử lý đồng thời là lợi ích tốt nhất của xử lý song song. Tuy nhiên, có một số hạn chế khi chia nhỏ nhiệm vụ, ví dụ như khi giáo viên giao cho lớp N câu hỏi nhưng chúng ta không thể tìm được đủ N học sinh để chuẩn bị và hoàn thành các nhiệm vụ đó hoặc là các bài toán đều liên quan đến nhau, đáp án câu 1 là lời giải cho câu 2 chẳng hạn. Tóm lại qua bài viết này bạn đã hiểu 1 số khái niệm về cpu-gpu và xin chúc mừng là bạn bắt đầu nhập môn vào lập trình song song trên gpu bằg cuda-C 😆😆 OpenMP. Món này rất dễ nhưng khá ít người biết và sử dụng, nếu các bạn biết áp dụng thì cũng rất thú vị và làm cho code của chúng ta “chất” và “ngầu” vl luôn 😎. OpenMP là gì ?OpenMP là tên một tính năng built-in sẵn trong hầu hết các C++ compiler, bạn chỉ cần chỉ định option build khi compile code là có thể sử dụng ngay mà không cần link thêm bất cứ thư viện nào khác. OpenMP có thể được sử dụng để các LTV truyền đạt cho compiler biết rằng một số đoạn code nào đó là độc lập vào cần chạy song song với nhau ở các thread khác nhau để tăng tốc độ xử lý cho chương trình. Những compiler nào support OpenMP ?
Làm thế nào để có thể sử dụng tính năng OpenMP trong C++ ?
Sử dụng Parallel Sections trong OpenMPCác xử lý mà bạn muốn chỉ thị cho compiler biết rằng chúng cần được chạy song song ở các thread khác nhau thì cần đặt vào trong các pragma omp section bên trongpragma omp parallel sections như code sample bên dưới →1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 include
include int main() { std::cout << "begin "; pragma omp parallel sections{ pragma omp section{ std::cout << "hello "; std::cout << "hello "; std::cout << "hello "; } pragma omp section{ std::cout << "world "; std::cout << "world "; std::cout << "world "; } } std::cout << "end" << std::endl; return 0; } 2 section với “ pragma omp section” ở đằng trước này sẽ được chạy song song ở 2 thread khác nhau. Chính vì vậy nếu bạn chạy code ở trên thì mỗi lần chạy có thể sẽ ra một kết quả khác nhau. Bên dưới lài kết quả một số lần chạy của mình (trên Visual Studio 2015) →begin hello hello hello world world world end # lần 1 begin hello world hello hello world world end # lần 2 begin hello hello hello world world world end # lần 3 begin hello hello world world world hello end # lần 4 Sử dụng Parallel For Loop trong OpenMPKhi các bạn muốn xử lý đặt bên trong một vòng for nào đó được tự động phân chia và chạy song song ở các thread khác nhau thì bạn dùng “ pragma omp parallel for” →1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 include
include int main() { int arr[16]; // parallel for loop printf("Assign value of arr[]:\n"); pragma omp parallel forfor (int i \= 0; i < 15; ++i) { arr[i] \= i; printf(" Thread %d: arr[%d] = %d\n", omp_get_thread_num(), i, arr[i]); } // normal for loop printf("=====================\n"); printf("Check value of arr[]:\n"); for (int i \= 0; i < 15; ++i) { arr[i] \= i; printf(" arr[%d] = %d\n", i, arr[i]); } return 0; } Ở ví dụ trên thì code bên trong vòng for sẽ được tư động chia ra chạy trên nhiều thread, số lần lặp trên mỗi thread sẽ được chia đều nhất có thể giữa các thread. Ở trên do không chỉ định số lượng thread nên số lượng thread sẽ được allocate tự động. Chương trình trên mỗi lần chạy khác nhau có thể print ra màn hình khác nhau nhưng kết quả cuối cùng là giá trị của array arr thì sẽ giống nhau. Dưới đây là kết quả một trong số các lần chạy của chương trình → 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 Assign value of arr[]: Thread 0: arr[0] \= 0 Thread 0: arr[1] \= 1 Thread 1: arr[4] \= 4 Thread 1: arr[5] \= 5 Thread 1: arr[6] \= 6 Thread 2: arr[8] \= 8 Thread 2: arr[9] \= 9 Thread 2: arr[10] \= 10 Thread 2: arr[11] \= 11 Thread 0: arr[2] \= 2 Thread 0: arr[3] \= 3 Thread 1: arr[7] \= 7 Thread 3: arr[12] \= 12 Thread 3: arr[13] \= 13 Thread 3: arr[14] \= 14 \===================== Check value of arr[]: arr[0] \= 0 arr[1] \= 1 arr[2] \= 2 arr[3] \= 3 arr[4] \= 4 arr[5] \= 5 arr[6] \= 6 arr[7] \= 7 arr[8] \= 8 arr[9] \= 9 arr[10] \= 10 arr[11] \= 11 arr[12] \= 12 arr[13] \= 13 arr[14] \= 14 Ta có thể thấy vòng for được chia ra và chạy trên 4 thread có id lần lượt là 0, 1, 2 và 3. Nếu muốn chỉ định chính xác số lượng thread sử dụng thì có thể dùng hàm omp_set_num_threads(), code dưới đây sẽ chỉ định sử dụng 2 thread → 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 include
include int main() { int arr[16]; omp_set_num_threads(2); // parallel for loop printf("Assign value of arr[]:\n"); pragma omp parallel forfor (int i \= 0; i < 15; ++i) { arr[i] \= i; printf(" Thread %d: arr[%d] = %d\n", omp_get_thread_num(), i, arr[i]); } // normal for loop printf("=====================\n"); printf("Check value of arr[]:\n"); for (int i \= 0; i < 15; ++i) { arr[i] \= i; printf(" arr[%d] = %d\n", i, arr[i]); } return 0; } Chạy thử và ra kết quả như sau, vòng for chỉ chạy trên 2 thread (id = 0, 1) nhưng kết quả cuối cùng của arr[] thì vẫn vậy → 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 Assign value of arr[]: Thread 0: arr[0] \= 0 Thread 0: arr[1] \= 1 Thread 0: arr[2] \= 2 Thread 1: arr[8] \= 8 Thread 0: arr[3] \= 3 Thread 0: arr[4] \= 4 Thread 0: arr[5] \= 5 Thread 0: arr[6] \= 6 Thread 0: arr[7] \= 7 Thread 1: arr[9] \= 9 Thread 1: arr[10] \= 10 Thread 1: arr[11] \= 11 Thread 1: arr[12] \= 12 Thread 1: arr[13] \= 13 Thread 1: arr[14] \= 14 \===================== Check value of arr[]: arr[0] \= 0 arr[1] \= 1 arr[2] \= 2 arr[3] \= 3 arr[4] \= 4 arr[5] \= 5 arr[6] \= 6 arr[7] \= 7 arr[8] \= 8 arr[9] \= 9 arr[10] \= 10 arr[11] \= 11 arr[12] \= 12 arr[13] \= 13 arr[14] \= 14 Thực ra OpenMP còn nhiều cú pháp khác nữa nhưng mình xin tạm dừng về topic ở đây vì không muốn làm nó phức tạp thêm, nên sử dụng ở mức simple như thế này là đủ, mình nghĩ vậy. Nếu anh em nào muốn tìm hiểu thêm thì cứ Google Search keyword “OpenMP C++” sẽ ra cả mớ. |