Giới thiệu

– Khi bắt đầu lập trình các ứng dụng phức tạp trên hệ điều hành Linux nói riêng hay các nền tảng có sử dụng hệ điều hành nói chung. Một phương pháp phổ biến mà chúng ra hay dùng là sử dụng thread (luồng) để đồng thời xử lý nhiều công việc cùng một lúc để tận dụng tối đa tài nguyên CPU.

– Tuy nhiên, thread cũng chưa hoàn toàn tận dụng hết toàn bộ sức mạnh của CPU, đối với các CPU nhiều core thì các hãng sản xuất phần mềm vẫn ưu tiên việc thiết kế multi-process (đa tiến trình) hơn là multi-thread(đa luồng).

– Một trong những phần mềm phổ biến thiết kế theo mô hình multi-process là chrome. Nếu bạn dang dùng Linux có thể sử dụng command ps hoặc top để liệt kê các process đang chạy.

– Có thể thấy rất nhiều instance (các process khác nhau của cùng 1 ứng dụng) của chrome đang chạy.

Ưu nhược điểm của việc sử dụng thread và process.

Sử dụng multi-process.

– Rất nhiều người phàn nàn rằng Chrome “ăn” RAM quá nhiều. Google chắc chắn nhận nhiều phàn nàn kiểu này nhưng tại sao họ không thay đổi ? Lý do đằng sau là gì?

– Để trả lời câu hỏi trên ta phải đi trả lời nguyên tắc hoạt động của các ứng dụng multi-process. Khi một process (application) được triệu gọi, hệ điều hành sẽ load mã thực thi của chương trình vào bộ nhớ RAM, cấp phát vùng nhớ cho các biến khai báo trong chương trình và thực hiện chạy chương trình.

– Khi một process khác được gọi (hoặc chạy lại chính process ở trên) thì hệ điều hành cũng thực hiện tương tự
(load mã chương trình, cấp phát vùng nhớ). Và điều quan trọng là vùng nhớ cho mã lệnh và vùng nhớ cho biến
của các process khác nhau là hoàn toàn tách biệt nhau. Nghĩa là process A không thể truy cập vùng nhớ của
process B.

– Việc phân lập như vậy có nhược điểm sẽ tốn bộ nhớ rất nhiều vì các process cứ phải nhân bản lại toàn bộ mỗi lần khởi chạy, đây là vấn đề tốn RAM mà Chrome đang gặp phải.

– Để giải quyết vấn đề tốn RAM ở trên chúng ta có thể sử dụng thread. Các thread được phát sinh bên trong một process do đó cùng chia sẽ với nhau không gian vùng nhớ chương trình và vùng nhớ biến. Ví dụ như thế này, trong chương trình chính bạn khai báo một biến toàn cục a thì trong thread A và thread B bạn có thể tương tác với biến a này mà không cần phải làm gì thêm. Điều này không dễ dàng gì đối với các process khác nhau.

Nhược điểm của thread.

– Đặc điểm chia sẽ vùng nhớ chương trình và vùng nhớ biến cũng chính là nhược điểm của thread. Nếu ứng dụng của bạn lớn, có sự tham gia phát triển của nhiều người, nhiều công việc khác nhau thì sẽ khó tránh khỏi sai lầm trong code khiến thread bị treo dẫn đến toàn bộ chương trình treo hoặc thậm chí tệ hơn là 1 thread bị crash dẫn đến toàn bộ chương trình crash theo. Google là một hãng lớn tất nhiên là không thích điều này.

 – Một đặc điểm phổ biến của các phần mềm hiện nay là cài đặt dạng plug-in. Ví dụ chrome bạn sẽ thấy các
extension, VScode cũng cung cấp việc cài đặt các extension … Và các Extension này được phát triển bởi rất
nhiều developer từ trình độ gà con cho tới đại bàng. Không ai đảm bảo code của các plug-in này không crash và có thể dẫn đến sụp đổ của toàn hệ thống. Giả sử như Chrome mà sử dụng single process, sau khi cài plug-in tự động dịch của anh dev Gà Con thì cứ mở lên chrome lên là crash. Là một người dùng thì bạn sẽ chẳng biết ngyên nhân do đâu, trước mắt cứ bảo Chrome “dởm quá” trước cái đã. Google sẽ không thích điều này.

 – Bây giờ mình sẽ viết một ứng dụng đơn giản mở 7 thread, ở thread thứ 6 mình sẽ cho thread crash, kết quả là toàn bộ chương trình crash theo.

– Chắc bạn đã nghe đến thuật ngữ CPU 4 core 4 luồng hay CPU 4 core 8 luồng hay đại loại ná ná vậy rồi đúng
không? Không phải cứ CPU nhiều core, nhiều luồng thì phần mềm sẽ chạy nhanh hơn đâu nhé, nó sẽ phụ thuộc
vào tốc độ xung nhịp CPU và cách thiết kế phần mềm nữa.

– Quay trở lại vấn đề, tại sao mình đề cập đến thuật ngữ “CPU 4 core 4 luồng hay CPU 4 core 8”. Với cách thiết kế “single-process” thì dù chương trình của bạn có quá tải hay cần yêu cầu resouce nhiều đến mấy thì hệ điều hành cũng chỉ dành tối đa cho bạn 1 Core của CPU để xử lý. Để chứng minh điều này mình viết một đoạn chương trình đơn giản, chẳng cần làm gì chỉ polling liên tục. 

– Đây là hoạt động của CPU ở trạng thái thông thường, các CPU đều hoạt động rất ít

– Và đây là trạng thái của CPU khi chạy cái app vô cùng đơn giản ở trên.

– Rõ ràng app main đang polling hết tốc lực, nhưng hệ điều hành chỉ cấp cho nó 1 core để chạy, trong khi 7 core còn lại thì đang ngồi chơi. Với cách thiết kế phần mềm như thế này thì bạn có nâng cấp CPU lên 100 core thì hiệu suất vẫn như vậy thôi vì chỉ có 1 core xử lý mà thôi. Chỉ có cách nâng cấp xung nhịp thì mới may ra cải
thiện.

– Quay trở lại vấn đề của google, nếu Google thiết kế chrome kiểu này thì khi user mở 100 tabs, tốc độ load sẽ
như rùa bò, trong khi CPU thì không chạy bao nhiêu, lúc này User sẽ nói Chrome chạy chậm quá. Google không
thích điều này.

– Cũng với cái app main ở trên, mình sẽ chạy thêm 1 instance khác nữa (tương đương với việc có 2 process).

– Lúc này bạn thấy có thêm 1 core khác nữa đã được dùng. Tương tự như vậy nếu ta mở thêm 6 instance nữa thì 8 core của CPU sẽ được sử dụng triệt để.

– Như vậy với cách thiết kế multiple process chúng ta có thể sử dụng tối đa tài nguyên CPU, và software của
chúng ta sẽ có performance tốt nhất. → Google thích điều này.

– Một điểm đáng lưu ý nữa là bạn có thể thấy chương trình của mình có thể nói là vô cùng đơn giản, không làm gì cả nhưng có thể lấy hết toàn bộ 100% của 8 core trên CPU, nó tranh giành hết tài nguyên CPU của các phần mềm khác (thật ra thì hệ điều hành đã có cách phân chia để không ai bị thiệt). → Google không quan tâm, miễn sao phần mềm Google viết chạy ngon nhất là được.

– Và với cách thiết kế phần mềm đa tiến trình như trên thì bạn có nâng cấp phần cứng CPU lên bao nhiêu đi nữa thì phần mềm cũng có thể sử dụng hết.

– Trong ví dụ ở trên thì bạn có thể thấy từ instance (một bản chạy của một phần mềm) thứ 8 thì 8 core của CPU đã đươc sử dụng tối đa. Và nếu bạn khởi chạy thêm 1 instance thứ 9 thì lúc này hệ điều hành sẽ sử dụng cơ chế phân lịch, 1 core sẽ phục vụ mỗi instance trong một khoảng thời gian ngắn và chuyển sang phục vụ cho instance khác. Vì bản chất CPU đã chạy hết hiệu suất, bạn có tạo thêm nhiều process khác nhau nữa thì chúng cũng không hoàn toàn chạy song song với nhau.

– Như vậy phương pháp đa tiến trình có ưu điểm hơn hẵn đã rõ ràng, vấn đề còn lại là làm sao phối hợp hoạt động và giao tiếp giữa các process khác nhau để mang lại hiệu quả tối đa cho phần mềm.

Tổng kết.

– Google chấp nhận việc tốn RAM và tài nguyên để đổi lại mang lại trải ngiệm sử dụng chrome tốt nhất, ổn định nhất cho người dùng.

– Ưu điểm của việc thiết kế multi-process đã thấy rõ, tuy nhiên việc đồng bộ, phối hợp giữa các process phức tạp hơn việc giao tiếp và đồng bộ giữa các thread. Do đó cần nắm rõ các kỹ thuật đồng bộ liên tiến trình thì mới thật sự kiểm soát và tận dụng tối đa tài nguyên.

– Đây là bài viết cung cấp cho các bạn cái nhìn tổng quát về thread và process dựa trên những kinh nghiệm làm việc và quá trình phát triển phần mềm của mình.

– Việc hiểu chức năng và đặc điểm của thread và process trước khi đi sâu vào code sẽ giúp bạn dễ dàng hơn trong việc phát triển code sau này và nắm được ý đồ thiết kế khi đọc/phát triển code cho các dự án đã có.

– Trong các bài viết tiếp theo mình sẽ giới thiệu chi tiết hơn về cách phát triển phần mềm sử dụng thread và process và các vấn đề, lưu ý thiết kế liên quan đến nó.