Ngành công nghiệp phần mềm và việc hưởng lợi từ sự phát triển của ngành công nghiệp phần cứng

[Lược dịch từ bài báo The Free Lunch Is Over: A Fundamental Turn Toward Concurrency in Software]

Có một hiệu ứng thú vị được gọi là “Dù cho Andy [Grow] có đưa ra [nền tảng phần cứng hỗ trợ tốc độ xử lý dữ liệu] bao nhiêu thì Bill [Gates] cũng sẽ dùng hết”. Cho dù các CPU (bộ xử lý trung tâm) có nhanh tới mức nào, phần mềm rồi cũng sẽ tìm ra cách để tiêu thụ cho hết công suất của bộ xử lý. Ví dụ chúng ta tạo ra một CPU có thể xử lý nhanh gấp mười lần, thì phần mềm cũng sẽ có cách tăng lượng công việc cần phải xử lý lên gấp mười. Rất nhiều thế hệ phần mềm đã được hưởng sự tăng hiệu suất của bộ xử lý, mà không cần phải thay đổi gì trong cách lập trình cả, bởi vì các nhà sản xuất CPU (nhân tố chính yếu) và các nhà sản xuất bộ nhớ và ổ cứng (nhân tố thứ 2) đã đều đặn tạo ra các sản phẩm phần cứng nhanh và mới hơn. Công suất máy tính không chỉ được đo lường bởi clock speed (tốc độ xung nhịp), nhưng clock speed có thể xem là một yếu tố chỉ hướng. Chúng ta đã từng chứng kiến 500 MHz CPU phải nhường bước cho 1 GHz CPU, rồi 2 GHz CPU lại trở thành tiêu chuẩn mới cho máy tính và sự tăng trưởng cứ tiếp tục như thế. Ngày nay các thiết bị máy tính đang ở dòng clock speed là 4.4 GHz.

Câu hỏi chính ở đây là: Đến khi nào thì sự tăng trưởng này sẽ kết thúc? Sau tất cả, định luật Moore dự đoán sự tăng trưởng theo hàm số mũ, và hàm số mũ không thể tăng trưởng mãi mãi bởi vì nó chạm tới các giới hạn vật lý của phần cứng; tốc độ xung nhịp không thể nhanh hơn tốc độ của ánh sáng. Clock speed phải đến lúc chậm lại và cuối cùng là dừng lại hẳn. (Về cơ bản, định luật Moore áp dụng cho mật độ tăng trưởng của linh kiện bán dẫn (transistor), nhưng sự phát triển theo hàm số mũ cũng xảy ra tương tự đối với các chỉ số có liên quan chẳng hạn như clock speed).

Hơn 30 năm qua, các nhà phát triển CPU đã đạt được cách tăng hiệu suất xử lý của máy tính thông qua 3 phương pháp:

  • Clock speed -Tốc độ xung nhịp
  • Execution optimization flow – Tối ưu hóa dữ liệu thực thi
  • Cache – Bộ nhớ đệm

Tăng clock speed nghĩa là tăng số lượng chu kỳ (trong một đơn vị thời gian) của CPU. Tạo ra một CPU chạy nhanh hơn có nghĩa là làm cho CPU đó tốn ít thời gian hơn để xử lý cùng một khối lượng công việc. Tối ưu hóa dữ liệu thực thi có nghĩa là làm tăng khối lượng công việc trong một chu kỳ xung nhịp. Cuối cùng, tăng dung lượng bộ nhớ đệm trên vi mạch (on-die cache) đồng nghĩa với việc giảm tần suất sử dụng RAM. RAM xử lý dữ liệu chậm hơn CPU (bộ xử lý trung tâm) nên chúng ta càng muốn đặt dữ liệu gần với bộ xử lý trung tâm – mà không đâu bằng cách đặt dữ liệu ngay trên mặt vi mạch (on-die cache: bao gồm cả L1, L2 và L3 cache). Bộ nhớ đệm sẽ tiếp tục phát triển, hiện nay hầu hết nhà sản xuất đã cung cấp dung lượng 8 MB cho bộ nhớ đệm đặt trên vi mạch. Vậy những điều này có ý nghĩa gì với chúng ta?

Một điều vô cùng quan trọng mà chúng ta phải thấy đó là tất cả phương pháp này đều là phi – tương tranh (concurrency-agnostic). Cải tiến bất kì phương pháp nào trong số trên sẽ trực tiếp cải tiến các ứng dựng tuần-tự (sequential application), bao gồm: tính toán không – song song (nonparallel), đơn luồng (single – threaded), đơn – tiến trình (single – process), cũng như các ứng dụng sử dụng phương pháp tương tranh.

NHỮNG TRỞ NGẠI ĐỐI VỚI SỰ PHÁT TRIỂN TRUYỀN THỐNG

Mức phát triển hiệu suất của CPU đã đụng trần vào năm 2003. Hình 1 thể hiện lịch sử vi mạch Intel thông qua clock speed và số lượng linh kiện bán dẫn. Số lượng linh kiện bán dẫn tiếp tục tăng, ít nhất là ở thời điểm hiện tại. Nhưng clock speed hay tốc độ xung nhịp, lại là một câu chuyện hoàn toàn khác.

Figure 1: Biểu đồ hướng tăng trưởng của Intel CPU

Khoảng đầu năm 2003, đường biểu-đồ của clock speed đã bị phẳng đi thay vì tiếp tục đi thẳng. Điều đó thể hiện cho việc càng ngày càng khó để khai thác tốc độ xử lý câu lệnh do không chỉ bởi một mà rất nhiều các vấn đề vật lý, trong đó đáng chú ý là nhiệt (quá nhiều nhiệt sinh ra từ chip và quá khó để tiêu trừ chúng), năng lượng tiêu thụ (quá cao), và các vấn đề dòng rò.

Thử nhìn lại: chúng ta có 2 GHz CPU đã rất lâu (8/2001), đến đầu năm 2016 chúng ta mong chờ sẽ có 10 GHz CPU. Nhưng thực tế thì bao nhiêu? Ở thời điểm hiện tại chúng ta chỉ có tối đa 4.4 GHz (đã tính đến cả công nghệ Turbo Boost). Thật ra, Intel cũng có một số mẫu vi mạch chạy ở tốc độ cao hơn trong phòng lab – nhưng số vi mạch này sử dụng một lượng quá nhiều thiết bị làm mát – điều không thể áp dụng cho sản phẩm tiêu dùng.

Do đó trong một vài năm tới, việc cải tiến hiệu suất xử lý dữ liệu của vi mạch sẽ được khai thác bởi 3 cách tiếp cận – chỉ có một trong số chúng là giống cách tiếp cận cũ.

  • Hyperthreading – Siêu phân luồng
  • Multicore – Đa nhân
  • Cache – Bộ nhớ đệm

Siêu phân luồng nghĩa là chạy 2 hay nhiều luồng dữ liệu cùng một lúc bên trong một CPU đơn. Hiện nay CPU siêu phân luồng đã được ứng dụng – cho phép chạy một số câu lệnh cùng một thời điểm. Tuy nhiên điểm hạn chế ở đây là, cho dù CPU siêu phân luồng có một số phần cứng bổ sung chẳng hạn như các thanh ghi bổ sung, nó vẫn chỉ có duy nhất một bộ nhớ đệm, một khối xử lý tính toán, một khối xử lý dấu phẩy-động ( FPU = Floating Point Unit), và tóm lại là chỉ có một (khối) kiến trúc cho tất cả các khối xử lý cơ bản của CPU. Siêu phân luồng được coi là có thể tăng năng suất xử lý dữ liệu của máy tính từ 5% tới 15% cho các ứng dụng đa luồng được lập trình một cách tối ưu. Thậm chí, siêu phân luồng được đánh giá có thể tăng năng suất xử lý lên đến 40% trong các điều kiện lý tưởng khi ứng dụng ( dựa trên phương pháp) đa luồng được lập trình một cách cẩn thận nhất. Có thể thấy siêu phân luồng là một phương pháp rất tốt để tăng hiệu suất, nhưng sử dụng phương pháp này không bao giờ có thể làm cho hiệu suất máy tính tăng gấp đôi – và một điểm hạn chế nữa là phương pháp siêu phân luồng không hỗ trợ được gì cho các ứng dựng đơn-luồng ( single –threaded applications).

Đa nhân có nghĩa là chạy từ 2 CPUs trở lên trong cùng một vi mạch. Một vài vi mạch, chẳng hạn của Sparc và PowerPC hiện nay đã giới thiệu các phiên bản vi mạch đa nhân. Các thiết kế của Intel và AMD, cho dù khác nhau về mức độ tích hợp, cũng đã có các phiên bản vi mạch đa nhân của riêng mình. AMD nhìn chung tạo ra được một số điểm mạnh trong thiết kế hiệu suất, chẳng hạn như đã tích hợp rất tốt các chức năng hỗ trợ trên cùng một lớp vi mạch. Trong khi đó, Intel lúc đầu chỉ đơn thuần “dán” 2 CPU Xeon trên cùng một lớp vi mạch. Do đó mức tăng hiệu suất xử lý ban đầu cũng hoàn toàn giống như một dual – CPU, có nghĩa là hoàn toàn không có chuyện tăng gấp đôi năng suất xử lý dữ liệu cho dù trong điều kiện lý tưởng. Thêm nữa, hiện nay phương pháp đa nhân cũng chỉ hỗ trợ cho các ứng dụng đa luồng mà không hỗ trợ cho các ứng dụng đơn luồng.

Cuối cùng, dung lượng của bộ nhớ đệm đặt trên vi mạch ( on-die cache) được mong đợi sẽ tiếp tục phát triển, ít nhất là trong tương lai gần. Trong số 3 phương pháp trên, đây chính là phương pháp mang lại nhiều lợi ích nhất cho các ứng dụng hiện nay ( không kể là đơn luồng hay đa luồng). Sự phát triển tiếp tục của bộ nhớ đệm đặt trên vi mạch là một điều vô cùng quan trọng và mang lại lợi ích hiện hữu cho rất nhiều ứng dụng – đơn giản bởi vì thêm không gian chứa dữ liệu cũng đồng nghĩa với việc tăng tốc độ xử lý dữ liệu ( khỏi mất công nhập/xuất dữ liệu thông qua các khối đệm). Truy cập bộ nhớ từ RAM đồng nghĩa với việc xử lý dữ liệu chậm hơn từ 10 đến 50 lần so với truy cập dữ liệu từ một bộ nhớ đệm. Điều này có thể gây ngạc nhiên cho hầu hết người dùng máy tính bởi họ nghĩ việc truy cập bộ nhớ [từ RAM] là rất nhanh. Đúng là việc truy cập bộ nhớ từ RAM là rất nhanh – nhưng là nhanh so với bộ nhớ đĩa và bộ nhớ các mạng liên kết ( networks), nhưng không là gì cả nếu so sánh với tốc độ của bộ nhớ đệm. Nếu toàn bộ dữ liệu của một ứng dụng có thể đặt gọn trong một bộ nhớ đệm, chúng ta sẽ có được một tốc độ xử lý lý tưởng hay tốc độ xử lý “vàng”. Do đó rất nhiều ứng dụng hiện nay trông chờ vào sự tăng dung lượng của bộ nhớ đệm như là cứu cánh để không phải thiết kế lại từ đầu cấu trúc lập trình của ứng dụng ( các ứng dụng qua năm tháng sẽ nạp thêm dữ liệu, cần thêm nhiều bộ nhớ để chứa dữ liệu đồng nghĩa với việc truy cập dữ liệu sẽ lâu hơn). Cụ thể là : các ứng dụng sẽ phải thao tác với nhiều dữ liệu hơn, bản thân ứng dụng sẽ phải nạp thêm nhiều câu lệnh lập trình để cập nhập các đặc tính mới, do đó các câu lệnh – nhạy cảm với hiệu suất xử lý dữ liệu cần phải được đặt vào trong bộ nhớ đệm ( để không làm chậm lại quá trình xử lý).

Ý nghĩa của sự thay đổi trên tới việc lập trình

Trong những năm 90, chúng ta lập trình dựa trên đối tượng ( lập trình hướng – đối tượng). Sự thay đổi cơ bản và có ảnh hưởng lớn nhất của cách mạng phần mềm trong hơn 30 năm qua chính là việc chuyển từ việc lập trình dựa vào cấu trúc phần cứng ( của máy tính) tới việc lập trình dựa vào đối tượng.

Như đã trình bày ở trên, các ứng dụng phần mềm của chúng ta vẫn sẽ được hưởng lợi trong việc hiệu năng suất xử lý dữ liệu do dung lượng bộ nhớ đệm đặt trên vi mạch vẫn đang tiếp tục được cải tiến. Nhưng nếu các chương trình phần mềm muốn được hưởng lợi theo năng suất hàm số mũ của các bộ xử lý, nó phải được lập trình lại theo phương pháp tương tranh ( tức là đa luồng). Và việc tái cấu trúc kỹ thuật lập trình theo phương pháp tương tranh thì nói dễ hơn là làm – bởi vì về bản chất, việc tái cấu trúc kỹ thuật lập trình là rất khó.

Cần làm rõ một điều là phương pháp tương tranh sẽ không tạo nên một cuộc cách mạng ngay lập tức. Chúng ta nhớ lại rằng phương pháp hướng – đối tượng đã được sử dụng bởi một số lượng nhỏ các nhà lập trình ngay từ thập niên 60s. Nhưng phương pháp hướng – đối tượng đã không thể trở thành một cuộc cách mạng ở thời điểm ấy mà phải chờ tới thập niên 90s để trở thành tiêu chuẩn mới của kỹ thuật lập trình. Tại sao lại như vậy? Lý do cuộc cách mạng hướng – đối tượng xảy ra là bởi vì ngành công nghiệp phần mềm đã đứng trước các đòi hỏi cấp thiết phải tạo ra các ứng dụng càng ngày càng lớn hơn để giải quyết các vấn đề càng lúc càng phức tạp hơn và khai thác các tài nguyên CPU ( cũng như các tài nguyên phần cứng khác) càng lúc càng nhiều hơn. Sức mạnh của lập trình hướng đối tượng trong việc trừu tượng hóa và quản lý phụ thuộc ( dependency managment) khiến nó trở thành một nhu cầu để có thể phát triển thành công các đặc tính cần có của các ứng dụng lớn :  tính kinh tế, tính khả tín và tính ổn định.

Tương tự như vậy, rất nhiều nhà lập trình đã ứng dụng phương pháp tương tranh từ rất lâu – từ thời của các câu lệnh đồng bộ đầu tiên như corroutines hay monitors. Và trong hơn 10 năm qua, chúng ta chứng kiến càng ngày càng nhiều các nhà lập trình viết chương trình theo phương pháp tương tranh ( đa luồng, đa – tiến trình). Nhưng sẽ còn lâu để đạt tới cột mốc mà một cuộc cách mạng kỹ thuật lập trình có thể diễn ra khi ngày nay hầu hết các ứng dụng phần mềm vẫn còn đang được viết theo phương pháp đơn luồng. Ở thời điểm hiện tại, bạn có thể nghe nhiều người nói đến “cuộc cách mạng kế tiếp của phát triển phần mềm” – những người tuyên bố điều đó đơn thuần là đang nói về công nghệ được phát triển bởi công ty của họ. Đừng vội tin tưởng vào những tuyên bố như vậy. Các công nghệ mới thì thật sự thú vị và có thể mang lại một số lợi ích, nhưng các công nghệ mà có thể mang đến một cuộc cách mạng thật sự để làm thay đổi kỹ thuật lập trình của số đông người dùng thì thường là các công nghệ đã được tạo ra và ứng dụng xung quanh chúng ta một vài năm, vẫn đang phát triển đều đặn để có thể đạt đến cột mốc của phát triển bùng nổ. Bạn cần phải lưu ý rằng : bạn chỉ có thể dựa vào một cuộc cách mạng kỹ thuật phần mềm khi mà công nghệ của nó phải đủ trưởng thành và cứng cáp ( bao gồm có được các cộng đồng hỗ trợ lớn và các công cụ phát triển tích hợp cho các nhà lập trình) để có thể xây dựng các ứng dụng của mình. Thông thường, một công nghệ phần mềm mới phải trải qua ít nhất 7 năm trước khi đạt đến cột mốc ổn định để người dùng có thể sử dụng được nó ở quy mô lớn. Kết quả là, một cuộc cách mạng phần mềm chẳng hạn như hướng – đối tượng thường phải trải qua nhiều năm, thậm chí nhiều thập kỉ của tinh chỉnh và phát triển liên tục trước khi đạt đến cột mốc để tạo ra một cuộc cách mạng. Một so sánh thú vị với các diễn viên Hollywood, nếu chúng ta phán xét một cách khách quan thì hầu hết các ngôi sao nổi tiếng sau một đêm cũng đều đã phải trải qua rất nhiều năm đóng những vai diễn bình thường không ai nhớ tới trước khi họ đạt đến độ chín để có thể tạo ra một vai diễn bùng nổ.

Phương pháp tương tranh sẽ là một cuộc cách mạng kế tiếp của ngành công nghệ lập trình, thay thế cho phương pháp hướng – đối tượng. Các chuyên gia đã và vẫn đang có những ý kiến khác nhau về việc liệu phương pháp tương tranh có thể tạo được tầm ảnh hưởng như hướng – đối tượng đã từng làm hay không. Nhưng nếu chỉ dựa trên quan điểm của một nhà công nghệ, phương pháp tương tranh hoàn toàn có cùng cấp độ với hướng – đối tượng khi xét tới quy mô của cuộc cách mạng mà nó tạo ra cũng như mức độ phức tạp và lợi thế của nó so với kỹ thuật lập trình trước đó.

Các hệ quả

  1. Hệ quả tất yếu nhất mà chúng ta đã thấy được ở phần trên là các ứng dụng cần phải được tăng cường phát triển theo phương pháp tương tranh để có thể tận dụng tối đa độ tăng hiệu suất của CPU. Ví dụ, Intel dự định sẽ tung ra một vi mạch bao gồm 100 nhân trong một vài năm tới, một ứng dụng đa luồng dù được lập trình tối ưu đến đâu cũng sẽ chỉ có thể khai thác được tối đa là 1/100 thông lượng tiềm năng của vi mạch đó. Tuy nhiên, điều đó cũng không có nghĩa phương pháp tương tranh sẽ khai thác được 100% công suất của một vi mạch như vậy. Một người phụ nữ cần 9 tháng để sinh một em bé hoàn toàn không đồng nghĩa với việc 9 người phụ nữ có thể sinh một em bé trong vòng một tháng. Nhiều người sử dụng ví dụ này như là một hạn chế của phương pháp tương tranh. Thật ra phương pháp tương tranh có mang lại lợi ích hay không hoàn toàn phụ thuộc vào cách chúng ta đặt ra mục tiêu cho ứng dụng. Nếu mục tiêu là sản xuất một em bé, phương pháp tương tranh sẽ không có nhiều ý nghĩa. Nhưng nếu mục tiêu là sản xuất 100 em bé, phương pháp tương tranh có thể chỉ tốn 1/100 lượng thời gian để xử lý so với phương pháp hướng – đối tượng. Hiểu rõ mục đích của ứng dụng sẽ tạo ra một khác biệt lớn trong kỹ thuật lập trình – chúng ta có thể gọi kỹ thuật lập trình mới là phương pháp hướng – mục đích.
  2. Một hệ quả tiếp theo ít người nhận ra hơn chính là việc hiệu suất của các ứng dụng đang ngày càng dịch chuyển theo hướng phụ thuộc vào định thời – CPU hơn thay vì phụ thuộc định thời – đầu vào/đầu ra hay định thời – dữ liệu như trước đây. Chúng ta đang ở dòng xung nhịp 4.4 GHz. Giá trị xung nhịp này sẽ hầu như không tăng được nữa trừ khi bộ nhớ đệm có thể tiếp tục tăng trưởng. Nếu dữ liệu của một ứng dụng tiếp tục tăng lên nhanh chóng, CPU sẽ đến một ngày không thể đáp ứng được nhu cầu xử lý dữ liệu ngày một lớn của ứng dụng nữa , trừ khi ứng dụng đó được thiết kế lại theo phương pháp lập trình tương tranh.
  3. Tối ưu hóa hiệu suất và hiệu quả chương trình phần mềm sẽ ngày một trở nên quan trọng. Hệ quả thứ 3 này chính là được sinh ra từ hệ quả 2. Các chương trình ứng dụng cần phải được tối ưu lại theo hướng gọn nhẹ hơn (để có thể xử lý nhiều công việc trong cùng một chu kì xung nhịp, dẫn đến thời gian xử lý dữ liệu toàn chương trình sẽ giảm xuống). Việc phát triển bền vững các ứng dụng tạo ra nhu cầu cần có các hệ thống và ngôn ngữ hướng – năng suất.
  4. Cuối cùng, các ngôn ngữ lập trình cần được thiết kế để làm việc tốt với phương pháp tương tranh. Ngôn ngữ Java đã hỗ trợ cho phương pháp tương tranh ngay từ thời điểm ban đầu, đã tinh chỉnh nhiều lần tính năng hỗ trợ qua nhiều lần cập nhập mới để giúp cho việc lập trình theo phương pháp tương tranh ngày càng hiệu quả và chính xác. Ngôn ngữ C++ cũng đã hỗ trợ lập trình đa luồng từ rất lâu nhưng vẫn chưa tiêu chuẩn hóa các công cụ hỗ trợ cho phương pháp tương tranh. Cuối cùng có một vài tiêu chuẩn cho phương pháp tương tranh chẳng hạn như pthread và OpenMP và một vài trình biên dịch từ đơn luồng sang tương tranh. Có một trình biên dịch từ đơn luồng sang tương tranh thì cũng tiện ích và thú vị, nhưng hầu hết các trình biên dịch này thường rất bị giới hạn về tính năng và bạn cũng không tăng thêm được bao nhiêu mức độ hiểu biết của mình về phương pháp tương tranh nếu so với việc bạn tự mình viết chương trình theo phương pháp này. Cần phải nói rằng, lập trình tương tranh dựa vào cú pháp lock thì không an toàn và dễ gây lỗi biên dịch. Do đó, chúng ta thực sự rất cần một mô hình ngôn ngữ lập trình bậc cao mới dành riêng cho phương pháp tương tranh thay vì các phương pháp chúng ta có hiện nay.
Chia sẻ bài viết

Leave a Comment

Your email address will not be published. Required fields are marked *