Tính toán song song trên dữ liệu: – Phần 2: Lập trình song song kiểu cổ điển

Trong phần 2 với tựa đề “Parallel prorgamming”, bằng cách nêu lên 3 khó khăn chủ đạo trong mô hình lập trình song song truyền thống là:

  • Cách suy nghĩ tuần tự của lập trình viên
  • Khả năng mở rộng hiệu năng (performance scaling)
  • Sự chuyển đổi thuật toán từ tuần tự sang song song hết sức tốn kém về thời gian và nhân lực

Chas đã dẫn dắt người đọc đến với yêu cầu về một mô hình lập trình song kiểu mới linh hoạt hơn và theo sát với sự thay đổi về số lượng nhân /lõi của một hệ thống máy tính.

Chúng ta hãy thử cùng tác giả tìm hiểu chi tiết hơn về 3 khó khăn nói trên xem sao.

* Khó khăn thứ nhất – Suy nghĩ tuần tự

Tôi còn nhớ như in ngày đầu tiên tôi được học lập trình trên chiếc máy tính XT cổ lỗ sĩ ở trường Tổng hợp cách đây gần 18 năm. Thầy hướng dẫn ra lệnh cho đám nhốn nháo TH1 lần đầu tiên được ngồi cạnh máy tính gõ từng lệnh của một chương trình viết bằng ngôn ngữ Pascal, trên bộ soạn thảo tích hợp Turbo Pascal. Hồi đó máy tính còn là một thứ hết sức quý hiếm với dân Sài gòn, đặc biệt là với sinh viên nghèo như tụi tui, nên giờ thực hành bà con hết sức chăm chỉ ngồi “gõ” chương trình. Ai có tiền hơn thì đi thuê phòng máy ở ngoài để “gõ” trước, rồi vô giờ thực hành tranh thủ nhờ thầy cô sửa lỗi giùm. Mà ngay cả đi thuê máy cũng khó khăn, phải đăng ký trước, rồi mỗi người chỉ được thuê 1, 2 tiếng chẳng hạn. Cho nên sinh viên tin học thời đó rất siêu môn gọi là “chạy chương trình chay” trên giấy, nghĩa là tự viết chương trình hết sức rõ ràng đầy đủ trên giấy (chứ còn chưa có bản in kim nữa là), rồi cùng nhau chạy bằng “miệng”, lẩm nhẩm từng bước một, ghi kết quả ra giấy để coi đúng không. Giờ nghĩ lại hồi đó làm vậy được là vì chương trình được viết ra để chạy tuần tự theo kiểu kiến trúc đơn luồng von Neumann, hết lệnh này tới lệnh khác (nói chữ nghĩa hơn là “có tính tất định” – deterministic), nên biết chắc được kết quả ở từng bước nếu mình không chạy sai về thứ tự thực thi. Cũng chính vì thói quen suy nghĩ tuần tự đã ăn sâu như vậy nên giờ chuyển sang suy nghĩ kiểu song song rất là mệt mỏi, vì sẽ phải chú ý tới các lỗi đặc thù của nó, nào là khóa chết (deadlock), rồi khóa sống (livelock), rồi điều kiện cạnh tranh, … rất khó nhận biết, và quan trọng hơn là các lỗi này thường không lập lại được để biết coi nguyên nhân từ đâu (tiếng Anh gọi là nonrepeatable error) để sửa chữa. Ngành khoa học máy tính đã tốn vài chục năm vừa rồi để đề ra nhiều phương pháp giải quyết, nhưng chưa đâu vào đâu cả.

Suy nghĩ kỹ hơn chúng ta có thể thấy rằng vụ tư duy tuần tự này là do môi trường lập trình quyết định. Từ thập niên 80 đến khoảng gần đây, chúng ta chủ yếu làm việc với máy tính cá nhân, và mô hình thực thi trên đó như đã nói là từng bước một. Cũng có máy tính song song, nhưng hiếm người được dùng nó trong công việc hàng ngày, vì chuyện xây dựng một hệ máy tính như vậy ở mức quốc gia đã cực kỳ tốn kém chứ đừng nói là công ty hay cá nhân. Còn bản thân con người hoàn toàn không xa lạ gì với chuyện ứng dụng xử lý song song trong đời sống hàng ngày. Dân tin học mê kiếm hiệp tụi tui vẫn nói đùa là Châu Bá Thông là ông tổ lập trình song song, do hai tay có thể thi triển hai loại võ công tuyệt thế khác nhau cùng lúc. Hay khi mình đi siêu thị mua đồ rồi trả tiền, thay vì phải xếp một hàng dài, bà con nghĩ liền đến chuyện lập nhiều quầy thu ngân cùng lúc cho lẹ. Hoặc đường cao tốc có nhiều làn xe là một ví dụ tương tự nữa minh họa hết sức rõ ràng về xử lý song song. Đó là ở quy mô xã hội. Còn với mỗi người, chuyện tranh thủ làm nhiều thứ cùng lúc cũng là bình thường, ví dụ như bấm nồi cơm điện, bắt ấm nước sôi, rồi tranh thủ rửa chén, ba cái sẽ xong cùng một lúc. Rõ ràng mình có thể liệt kê rất nhiều ví dụ nữa kiểu như vậy.

* Khó khăn thứ hai – Mở rộng hiệu năng

Qui tắc Amdahl trong lập trình song song cho chúng ta biết là lượng tăng tốc tối đa có thể đạt được bằng việc song song hóa thuật toán thì tỷ lệ nghịch với phần mã chương trình không thể chuyển sang dạng song song. Nói nôm na là cho dù chỉ còn 10% mã chương trình không thể song song hóa, thì sự tăng tốc chương trình đó cũng không vượt quá 10 lần. Tuy nhiên để ướng lượng mức độ cải tiến theo kiểu này rất khó, vì không thể xác định chính xác bao nhiêu phần trăm mã chương trình thật sự chạy song song, do trong lúc thực thi song song, mọi thứ lại rất có thể bị chuyển ngược lại thành tuần tự, như khi có tranh chấp tài nguyên dùng chung, hay có truy cập đến nhiều vị trí khá cách xa nhau trong bộ nhớ. Đây chính là một trong những hạn chế chính của mô hình lập trình song truyền thống (vốn thường cài đặt cách điều khiển tiểu trình qua cơ chế khóa, hay qua giao diện truyền thông điệp, hay nhiều cách khác nữa đòi hỏi sự đồngbộ hóa – nói nôm na là tiểu trình này đợi tiểu trình kia hoàn tất công việc rồi mới làm tiếp phần việc tiếp theo của mình) khi áp dụng cho nhiều nhân/lõi. Nói một cách dễ hiểu, nếu chúng ta chỉ phải đợi từng người một hoàn tất công việc của họ một cách độc lập, thì thời gian chờ đợi có thể coi là tăng tuyến tính với số người cần đợi/đồng bộ. Nhưng nếu chúng ta phải đợi cùng lúc nhiều người, và kết quả công việc của họ lại phụ thuộc lẫn nhau, thì thời gian chờ đợi sẽ tăng tổ hợp và rất khó xác định, chứ không đơn giản chỉ là tăng tuyến tính.

Còn có một khó khăn cơ bản hơn nữa trong mở rộng hiệu năng với số nhân/lõi. Mô hình lập trình song song truyền thống tiếp cận bài toán cần giải quyết theo kiểu top-down, bằng cách chia một bài toán lớn thành nhiều tác vụ con, và mỗi tác vụ này sẽ được giao cho một bộ xử lý/nhân/lõi. Vấn đề rắc rối ở đây là khi số lượng bộ xử lý/nhân/lõi tăng lên đến hàng chục, hay hàng trăm như hiện nay, thì số tác vụ con đã được thiết kế để giao nhằm tận dụng sức mạnh tính toán của chúng lại không có đủ.
Cách tiếp cận phổ biến nhất cho tình huống này là lại cố chia nhỏ các tác vụ con đó thành nhiều đơn vị thực thi nhỏ hơn.
Như vậy, cách làm này bị phụ thuộc vào từng thế hệ phần cứng bộ xử lý, dẫn đến chuyện không thể mở rộng việc thực thi chương trình một cách dễ dàng theo kiểu không cần phải thay đổi, sửa chữa gì về mặt thuật toán hay mã nguồn cài đặt. Và suy cho cùng thì nếu một bài toán mà được chia thành vài chục tác vụ con chạy song song sẽ vô cùng khó quản lý và gỡ rối.

* Khó khăn thứ ba – Tuần tự sang song song

Chuyện đau khổ nhất trong việc cố gắng chuyển mã từ tuần tự sang song song dựa trên tác vụ là ở chỗ quá trình này cần rất nhiều thời gian, có khi cả vài năm trời. Do tốc độ gia tăng số nhân/lõi hiện tại quá nhanh, nên nhiều khi thuật toán song song mà chúng ta đã bỏ ra vài năm kể từ năm nay để thiết kế lại không mở rộng tốt với số nhân/lõi của vài năm nữa, ở thời điểm chúng ta hoàn tất việc cài đặt nó một cách song song. Vậy là coi như mọi cố gắng sẽ thành công cốc!!!

Thật ra ý tưởng gán một công việc nhỏ cho từng bộ xử lý/nhân/lõi trong máy tính nhằm tăng hiệu năng phần mềm chạy trên đó là hoàn toàn tự nhiên và được đúc kết từ kinh nghiệm trong đời sống hàng ngày. Tuy nhiên để tận dụng được hết sức mạnh của hàng trăm, rồi hàng ngàn nhân/lõi trong tương lai, chúng ta có lẻ cần phải “đi trước đón đầu” bằng cách tạo ra hàng chục ngàn, hàng trăm ngàn công việc nhỏ li ti cung cấp cho đội quân nhân/lõi đông đảo và ngày một gia tăng đó. Ở đâu ra  một khối lượng lớn các “tiểu tác vụ” như vậy?

Lời giải nằm ở chỗ bạn đừng quan tâm đến số lượng các tác vụ cần thực hiện, mà hãy để mắt đến khối lượng dữ liệu mà bạn cần xử lý. Chẳng hạn, có nhiều nhất bao nhiêu điểm ảnh có thể xử lý độc lập với một ảnh HD 1920 x 1080?

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: