# 57: Mẹo giúp cải thiện hiệu quả của các hệ thống xử lý song song

Các lập trình viên ngay từ đầu đã được dạy rằng việc lập trình đồng thời là một vấn đề rất khó, đặc biệt đối với việc xử lý song song, rằng chỉ có những lập trình viên xuất sắc nhất mới có thể vận dụng nó một cách đúng đắn, và ngay cả những người xuất sắc đó cũng đã mắc sai lầm. Có vô số các lý thuyết về luồng, các cột mốc, các tiến trình, và rất khó để có thể truy cập vào các for programming biến trong luồng một cách an toàn.

Thật vậy, có rất nhiều vấn đề nan giải. Nhưng gốc rễ của chúng là gì? Chia sẻ bộ nhớ. Hầu hết các vấn đề của lập trình đồng thời mà mọi người gặp phải đều liên quan việc chia sẻ một bộ nhớ có thể bị biến đổi (do quá trình xử lý luồng): race conditions, deadlock, livelock, v.v…. Câu trả lời dường như rất rõ ràng: hoặc là từ bỏ đồng thời hoặc tránh chia sẻ bộ nhớ.

Gửi đồng thời gần như chắc chắn không phải là một lựa chọn. Máy tính càng ngày càng có nhiều lõi hơn, do đó khai thác song song ngày càng trở nên quan trọng. Chúng ta không thể tăng tốc vi xử lý để cải thiện hiệu suất ứng dụng. Chỉ bằng cách khai thác song song thì hiệu suất của các ứng dụng sẽ được cải thiện. Rõ ràng, việc không cải thiện hiệu suất là một lựa chọn, nhưng khó có thể được người dùng chấp nhận.

Vậy, chúng ta có thể tránh chia sẻ bộ nhớ như thế nào? Chắc chắn rồi.

Thay vì sử dụng các luồng và chia sẻ bộ nhớ như mô hình lập trình của chúng ta, ta có thể sử dụng các tiến trình và thông báo truyền qua. Tiến trình này có nghĩa là một trạng thái độc lập được bảo vệ với mã thực thi, không nhất thiết phải là một tiến trình hệ điều hành. Các ngôn ngữ như Erlang (và trước đó là Occam) đã chỉ ra rằng các tiến trình là một cơ chế rất thành công để lập trình các hệ thống đồng thời và song song. Các hệ thống như vậy không có tất cả các ứng suất đồng bộ hóa mà bộ nhớ chia sẻ, các hệ thống đa luồng có. Hơn nữa, có một mô hình chính thức — Mô hình giao tiếp tuần tự (Communicating Sequential Processes — CSP) có thể được áp dụng như một phần kỹ thuật của các hệ thống đó.

Chúng ta có thể tiến xa hơn và giới thiệu các hệ thống dataflow như một cách tính toán. Trong một hệ thống dataflow, không có luồng điều khiển được lập trình rõ ràng. Thay vào đó, một biểu đồ hướng của các toán tử, được kết nối bằng đường dẫn dữ liệu, được thiết lập và sau đó dữ liệu được đưa vào hệ thống. Đánh giá được kiểm soát bởi sự sẵn sàng của các dữ liệu trong hệ thống. Chắc chắn không có vấn đề đồng bộ.

Điều đó nói rằng, các ngôn ngữ như C, C++, Java, Python và Groovy là ngôn ngữ chính của phát triển hệ thống và tất cả các ngôn ngữ này được trình bày cho lập trình viên là ngôn ngữ để phát triển bộ nhớ chia sẻ, hệ thống đa luồng. Vậy thì cái gì có thể làm được? Câu trả lời là sử dụng, hoặc nếu chúng không tồn tại, hãy tạo ra các thư viện và các framework cung cấp các mô hình tiến trình và thông điệp, tránh tất cả việc sử dụng bộ nhớ có thể thay đổi được chia sẻ.

Nói chung, không phải lập trình với bộ nhớ chia sẻ, mà thay vào đó là sử dụng thông điệp truyền đi, có thể là cách thành công nhất để thực hiện các hệ thống điều khiển song song hiện hữu trong phần cứng máy tính. Có lẽ kỳ lạ, mặc dù các tiến trình có trước các luồng như là một đơn vị đồng thời, trong tương lai dường như sẽ sử dụng các luồng để triển khai thực hiện các tiến trình.