Lập trình đa luồng không còn xa lạ với các nhà phát triển. Nếu bạn còn xa lạ với khái niệm này, hãy tham khảo tài liệu sau:
Multithreading in Operating System
Ngoài ra, bạn cũng có thể đọc qua hai bài viết sau:
Bài viết này sẽ tập trung vào việc tìm hiểu một số mô hình đa luồng phổ biến.
Boss-Worker
- Mô tả:
Mô hình này bao gồm một luồng chính (Boss) và nhiều luồng con (Worker). Luồng chính chịu trách nhiệm phân chia công việc cho các luồng con, và các luồng con sẽ xử lý các công việc được giao, các luồng có thể có logic độc lập nhau. - Ví dụ minh họa:
Trong dự án Mezon, A Nhàn (PO) là luồng Boss. A Nhàn phân chia các task công việc cho đội nhóm (Worker) để hoàn thành từng phần công việc, ví dụ như giao dev RB thay label color trên macbook, giao Thái fix bug, giao Diễm giải lại bài toán 9.11 và 9.9 …
Master-Slave
- Mô tả:
Trong mô hình này, trạm chủ (Master) chịu trách nhiệm điều phối và phân chia công việc. Các trạm tớ (Slave) thực hiện công việc theo lệnh và chỉ báo cáo kết quả về cho Master. - Các Slave thực hiện các nhiệm vụ cụ thể do Master giao, sau đó trả kết quả về.
Master có thể sử dụng phương pháp kiểm soát tuần tự (polling) để quản lý và tối ưu hóa giao tiếp giữa các Slave.
- Ví dụ minh họa:
A Nhàn có bài toán tính sum = a + b 1.000.000 lần. Để tối ưu, A Nhàn huy động toàn bộ nhân sự công ty NCC gồm 1000 người để tính toán.
Mỗi nhân viên (trừ người viết bài này :)) ) chỉ làm một nhiệm vụ duy nhất là tính toán các phép sum = a + b và trả kết quả cho A Nhàn (Master), mỗi nhân viên sẽ giải trung bình 1000 lần. Sau khi nhận đủ kết quả, A Nhàn xử lý bước tiếp theo.
người ta gọi đây là chế độ độc tài : )
Pipeline
- Mô tả:
Công việc được chia nhỏ thành nhiều bước liên tiếp. Mỗi bước sẽ được xử lý bởi một luồng riêng biệt. Các luồng hoạt động nối tiếp, khi một luồng hoàn thành công việc thì sẽ chuyển dữ liệu cho luồng kế tiếp. - Ví dụ minh họa:
Trong dự án Mezon:- A Nhàn (PO) nghĩ ra tính năng mới và chuyển cho BE dev Thái (luồng 1).
- BE dev Thái viết API xong, chuyển cho designer thiết kế giao diện (luồng 2), trong khi a Nhàn vẫn đang nghĩ thêm feature để hành Thái.
- Designer hoàn thành, chuyển cho FE phát triển (luồng 3).
- FE xong, chuyển cho tester kiểm thử (luồng 4).
- Tester báo cáo lỗi (nếu có), trong khi các luồng khác tiếp tục xử lý tính năng mới
Mô hình Producer-Consumer
- Mô tả:
Đây là mô hình phổ biến trong các hệ thống chia sẻ tài nguyên giữa các luồng. Một hoặc nhiều luồng sản xuất (Producer) tạo dữ liệu và đưa vào hàng đợi. Một hoặc nhiều luồng tiêu thụ (Consumer) lấy dữ liệu từ hàng đợi và xử lý. - Ví dụ minh họa:
- A Nhàn là Producer đi tìm dự án outsource và đưa dự án kiếm được vào hàng đợi.
- A Phúc Consumer lấy dữ liệu từ hàng đợi để đi phỏng vấn dự án.
- Nếu hàng đợi rỗng thì a Phúc sẽ ngồi đánh bi lắc ăn tiền với a Tiến
Mô hình Fork-Join
- Mô tả:
Một tác vụ lớn được chia thành nhiều tác vụ con, và các tác vụ này được thực hiện song song. Sau khi tất cả các tác vụ con hoàn thành, kết quả được kết hợp lại để đưa ra kết quả cuối cùng. - Ví dụ minh họa:
Bài toán trồng trọt chăn nuôi:- A Nhàn muốn trồng 1 lượng lớn nông sản đem bán, a giao a Phúc chăn nuôi và chị Yến cho lĩnh vực trồng trọt.
- A Phúc thu nạp thêm Nghĩa để phụ trách nuôi động vật trên cạn, con a phụ trách động vật dưới nước.
- Tiếp theo a Phúc thu nạp thêm Thái để nuôi tôm và a đi nuôi cá.
- Đến cuối ngày A Phúc nhận report của Thái
- Sau đó a nhận report của Nghĩa cho việc chăn nuôi động vật trên cạn
- Chị Yến cũng sẽ làm tương tự như a Phúc, chị kiếm người trồng cây, trồng lúa, trồng rau rồi chờ báo cáo từ họ
- Cuối cùng a Phúc và chị Yến tổng hợp mọi việc và thông báo cho a Nhàn
Thread Pooling (Luồng dùng chung)
- Mô tả:
Mô hình này sử dụng một nhóm luồng cố định (pool) để xử lý các tác vụ. Thay vì tạo luồng mới mỗi khi có công việc, các tác vụ được đưa vào hàng đợi và xử lý bởi các luồng có sẵn trong nhóm.
Mô hình này giúp giảm chi phí tạo và hủy luồng, đồng thời quản lý tài nguyên hệ thống hiệu quả hơn. - Ví dụ minh họa:
Trong hệ thống xử lý yêu cầu phát lương từ bộ phần Finance:- Các Finance gồm 10 người sẽ nhận yêu cầu nhận lương của nhân viên
- Khi nhận được yêu cầu mới, Finance sẽ yêu cầu nhân viên xếp hàng (hàng đợi). Các Finance trong pool lần lượt yêu cầu người dùng đứng đầu hàng đợi: “lên đây chị phát lương cho”.
- Sau khi hoàn thành, Finance đó sẽ quay lại trạng thái rảnh để tiếp tục nhận công việc mới.
Work Stealing (Trộm công việc)
- Mô tả:
Đây là một mô hình tối ưu hoá cho các hệ thống đa luồng khi các luồng có khối lượng công việc không đồng đều.
Nếu một luồng hoàn thành công việc của mình sớm hơn, nó có thể “trộm” công việc từ luồng khác để tăng hiệu suất sử dụng tài nguyên. - Ví dụ minh họa:
Trong một ứng dụng render video:- Mỗi khung hình (frame) được giao cho một luồng xử lý.
- Nếu một luồng xử lý nhanh hơn và không còn khung hình nào trong hàng đợi, nó sẽ lấy một khung hình từ hàng đợi của luồng khác để xử lý.
MapReduce (Ánh xạ – Giảm thiểu)
- Mô tả:
Đây là mô hình phổ biến trong xử lý dữ liệu lớn. Dữ liệu đầu vào được chia thành nhiều phần nhỏ, sau đó các luồng thực hiện hai bước chính:- Map: Chuyển đổi và xử lý từng phần dữ liệu nhỏ.
- Reduce: Gộp kết quả của tất cả các phần đã xử lý thành một kết quả duy nhất.
- Đây được coi là biến thể lỏng lẻo của Master-slave
- Ví dụ bài toán:
Anh Nhàn trộn gạo nếp, gạo tẻ, gạo lức, gạo Nhật vào với nhau và yêu cầu các cô Tấm trong ncc lọc gạo : và giả sử chúng ta có 10 cô tấm và có tổng cộng 100 kg gạo- Bước Map: mỗi cô tấm lượm 10kg gạo về mình và nhặt từng hột gạo và kết quả như sau
- Cô Tấm Thái cut666: 1kg gạo tẻ, 3kg gạo lức, 2kg gạo nếp, 4kg gạo Nhật
- Cô Tấm Mai: 2kg gạo tẻ, 4kg gạo lức, 3kg gạo nếp, 1kg gạo Nhật
- Cô Tấm Phúc: 1.5kg gạo tẻ, 3kg gạo lức, 3.5kg gạo nếp, 2kg gạo Nhật
- Cô Tấm Quân: 2kg gạo tẻ, 2.5kg gạo lức, 3kg gạo nếp, 2.5kg gạo Nhật
- Cô Tấm Diễm: 1.5kg gạo tẻ, 3.5kg gạo lức, 3kg gạo nếp, 2kg gạo Nhật
- Cô Tấm Thư: 2.5kg gạo tẻ, 2kg gạo lức, 3kg gạo nếp, 2.5kg gạo Nhật
- Cô Tấm Vinh: 2kg gạo tẻ, 3kg gạo lức, 2.5kg gạo nếp, 2.5kg gạo Nhật
- Cô Tấm Phong: 1kg gạo tẻ, 4kg gạo lức, 3kg gạo nếp, 2kg gạo Nhật
- Cô Tấm Tùng TH: 2kg gạo tẻ, 2kg gạo lức, 3kg gạo nếp, 3kg gạo Nhật
- Cô Tấm DuyNH: 2kg gạo tẻ, 3kg gạo lức, 2kg gạo nếp, 3kg gạo Nhật
- Bước Reduce: Sau khi các cô Tấm phân loại xong, tổng kết số lượng từng loại gạo
- Gạo tẻ: 18.5kg
- Gạo lức: 30kg
- Gạo nếp: 29kg
- Gạo Nhật: 25.5kg
- Và cuối cùng: A Nhàn đem gạo về nấu cháo gà ăn dần
- Bước Map: mỗi cô tấm lượm 10kg gạo về mình và nhặt từng hột gạo và kết quả như sau
Trên đây là một số mô hình phổ biến trong lập trình đa luồng. Hy vọng bài viết giúp bạn có thêm góc nhìn về cách tổ chức và tối ưu công việc khi làm việc với multithreading.