Kinh nghiệm thực tế khi tối ưu hóa mã nguồn C/C++ Ngoài việc có một trình biên dịch mạnh ra, thì người lập trình cần phải có kỹ năng tối ưu mã lệnh để có thể đánh giá tiêu chuẩn một sản phẩm tốt. Khi bắt đầu viết một chương trình bằng một ngôn ngữ nào đó, thông thường bạn chỉ chú trọng vào việc hoàn tất các tính năng của chương trình yêu cầu, việc tối ưu nó được đặt ra sau khi bạn hoàn thành chương trình đó. Do đó trong khi viết code bạn nên tạo cho mình một thói quen sao cho mã nguồn được tối ưu trong những trường hợp cơ bản. Bài viết dưới đây sẽ giúp các bạn hiểu hơn về tối ưu hóa mã nguồn C/C++, tại sao phải tối ưu hóa mã nguồn? tối ưu hóa mã nguồn như thế nào? Nó đem lại lợi ích gì cho người lập trình?… Những câu hỏi đó sẽ được trả lời trong bài viết này. Tại sao phải tối ưu mã lệnh? Xuất phát từ vấn đề đánh giá tiêu chuẩn một sản phẩm do một người lập trình làm ra, điều quan trọng không kém đó chính là tốc độ xử lí và kích thước của một chương trình. Bên cạnh đó, sự ra đời của trình biên dịch hiện đại giúp cải thiện và giảm tải thời gian công việc của lập trình viên đi một cách đáng kể, tuy nhiên chính vì mang tính đa năng ấy, làm cho kỹ năng viết mã lệnh hoàn toàn phụ thuộc vào sự hỗ trợ của trình biên dịch. Do đó, ngoài việc có một trình biên dịch mạnh ra, thì người lập trình cần phải có kỹ năng tối ưu mã lệnh để có thể đánh giá tiêu chuẩn một sản phẩm tốt. Kỹ năng tốt sẽ biến công việc lập trình khô khan, với các đoạn code tưởng chừng lạnh lùng trở nên sinh động. Một đoạn mã lệnh tốt sẽ tận dụng tối đa ưu điểm của ngôn ngữ và khả năng xử lý của hệ thống, từ đó giúp nâng cao đáng kể hiệu suất hoạt động của hệ thống. Hầu hết các trình biên dịch phổ biến hiện nay đều hỗ trợ tốt việc tối ưu mã khi biên dịch. Một số gợi ý cơ bản và kinh nghiệm thực tế tối ưu trong lập trình bằng ngôn ngữ C/C++: 1. Tinh giản các biểu thức toán học Các biểu thức toán học phức tạp khi được biên dịch có thể sinh ra nhiều mã dư thừa math làm tăng kích thước và chậm tốc độ thực hiện của chương trình. Do đó khi viết các biểu thức phức tạp lập trình viên cần nhớ một số đặc điểm cơ bản sau để giúp tinh giản biểu thức: - CPU xử lý các phép tính cộng và trừ nhanh hơn các phép tính chia và nhân. - CPU xử lý tính toán với các số nguyên (integer) chậm hơn với số thực (float, double), và tốc độ xử lý float nhanh hơn double. - Trong một số trường hợp nhân hoặc chia số nguyên, sử dụng toán tử dời bit (bit shifting) sẽ nhanh hơn toán tử nhân chia. 2. Tối ưu việc sử dụng biến tạm Đối với một số biểu thức tính toán số học phức tạp, trình biên dịch thường tạo các biến tạm trong bộ nhớ để chứa kết quả tính toán và cuối cùng mới gán giá trị này cho biến kết quả. Việc sử dụng biến tạm làm giảm tốc độ tính toán do phải cấp phát vùngvarialbe nhớ, tính toán và thực hiện việc gán kết quả cuối cùng. Để tránh việc sử dụng biến tạm, ta có thể thực hiện việc tách các biểu thức phức tạp thành các biểu thức nhỏ hơn hoặc sử dụng các mẹo cho việc tính toán. 3. Tối ưu các biểu thức điều kiện và luận lý Biểu thức điều kiện là thành phần không thể thiếu ở hầu hết các chương trình máy tính vì nó giúp lập trình viên biểu diễn và xử lý được các trạng thái của thế giới thực dưới dạng các mã lệnh máy tính. Một trong những tiêu chí quan trọng của việc tối ưu các biểu thức điều kiện là đưa các điều kiện có xác suất xảy ra cao nhất, tính toán nhanh nhất lên đầu biểu logic thức. - Đối với các biểu thức luận lý, ta có thể linh động chuyển các biểu thức điều kiện đơn giản và xác suất xảy ra cao hơn lên trước, các điều kiện kiểm tra phức tạp ra sau. - Đối với các biểu thức kiểm tra điều kiện phức tạp, ta có thể viết đảo ngược bằng cách kiểm tra các giá trị cho kết quả không thoả trước, giúp tăng tốc độ kiểm tra. 4. Tối ưu vòng lặp Vòng lặp cũng là một thành phần cơ bản phản ánh khả năng tính toán không mệt mỏi của máy tính. Tuy nhiên, việc sử dụng máy móc vòng lặp là một trong những nguyên nhân làm giảm tốc độ thực hiện của chương trình. Một số thủ thuật sau sẽ giúp lập trình viên tăng tốc vòng lặp của mình: - Đối với các vòng lặp có số lần lặp nhỏ, ta có thể viết lại các biểu thức tính toán mà không cần dùng vòng lặp. Nhờ vậy tiết kiệm được khoảng thời gian quản lý và tăng biến đếm trong vòng lặp. - Đối với các vòng lặp phức tạp có số lần lặp lớn, cần hạn chế việc cấp phát các biến nội bộ và các phép tính lặp đi lặp lại bên trong vòng lặp mà không liên quan đến biến đếm lặp. 5. Tối ưu việc sử dụng bộ nhớ và con trỏ Con trỏ (pointer) có thể được gọi là một trong những “niềm tự hào” của C/C++, tuy nhiên thực tế nó cũng là nguyên nhân làm đau đầu cho các lập trình viên, vì hầu hết các trường hợp sụp đổ hệ thống, hết bộ nhớ, vi phạm vùng nhớ… đều xuất phát từ việc sử dụng con trỏ không hợp lý. Hạn chế pointer dereference: pointer dereference là thao tác gán địa chỉ vùng nhớ dữ liệu cho một con trỏ. Các thao tác dereference tốn nhiều thời gian và có thể gây hậu quả nghiêm trọng nếu vùng nhớ đích chưa được cấp phát. Sử dụng tham chiếu (reference) cho đối tượng dữ liệu phức tạp trong các tham số hàm. Việc sử dụng tham chiếu khi truyền nhận dữ liệu ở các hàm có thể giúp tăng tốc đáng kể đối với các cấu trúc dữ liệu phức tạp. Một điểm cần lưu ý khi sử dụng tham chiếu là giá trị của đối tượng có thể được thay đổi bên trong hàm gọi, do đó lập trình viên cần sử dụng thêm từ khóa const khi không muốn nội dung đối tượng bị thay đổi. 6. Tận dụng một số ưu điểm khác của C++ Khi thiết kế các lớp (class) hướng đối tượng, ta có thể sử dụng các phương thức “inline” để thực hiện các xử lý đơn giản và cần tốc độ nhanh. Theo thống kê, các phương thức inline thực hiện nhanh hơn khoảng 5-10 lần so với phương thức được cài đặt thông thường. Sử dụng ngôn ngữ cấp thấp assembly: một trong những ưu điểm của ngôn ngữ C/C++ là khả năng cho phép lập trình viên chèn các mã lệnh hợp ngữ vào mã nguồn C/C++ thông qua từ khóa __asm { … }. Lợi thế này giúp tăng tốc đáng kể khi biên dịch và khi chạy chương trình. Ngôn ngữ C++ cho phép sử dụng từ khóa “register” khi khai báo biến để lưu trữ dữ liệu của biến trong thanh ghi, giúp tăng tốc độ tính toán vì truy xuất dữ liệu trong thanh ghi luôn nhanh hơn truy xuất trong bộ nhớ. Một chương trình được đánh giá tốt khi tất cả các bộ phận tham gia vào hoạt động của chương trình đạt hiệu suất cao nhất theo yêu cầu của người sử dụng. Một dòng lệnh đơn giản tưởng chừng sẽ hoạt động trong tích tắc có thể làm hệ thống trở nên chậm chạp khi được gọi hàng ngàn, hàng triệu lần trong khoảng thời gian ngắn. Do vậy, trong suốt quy trình hình thành sản phẩm phần mềm, giai đoạn cài đặt mã lệnh chiếm vai trò hết sức quan trọng và cần kĩ năng tối ưu hóa cao nhất. Để đạt được điều đó, không cách nào khác hơn là lập trình viên cần rèn luyện thật nhiều để thông thạo ngôn ngữ mình chọn lựa, trình biên dịch mình sử dụng. Khi đó lập trình không còn là việc tạo những đoạn mã khô khan, mà là một nghệ thuật. Nếu bạn yêu thích lập trình và muốn theo đuổi con đường đó, hãy tham gia các khóa học kinh nghiệm lập trình tại Stanford – dạy kinh nghiệm thực tế . Chúng tôi sẽ giúp bạn thành công. Tham gia khóa học lập trình, bạn sẽ được cung cấp kiến thức và kinh nghiệm làm việc thực tế, sử dụng thành thạo các công cụ phát triển phần mềm, phát triển kỹ năng làm việc nhóm và có cơ hội tham gia các dự án đang phát triển tại công ty. Là đơn vị tiên phong trong lĩnh vực đào tạo các lập trình viên phát triển phần mềm, Công ty CP Stanford – Đào tạo và phát triển công nghệ luôn quan niệm làm thế nào để mang đến kết quả tốt nhất cho học viên sau mỗi khóa học. Tại Stanford, các khóa học kinh nghiệm lập trình được khai giảng liên tục trong tháng như khóa học lập trình Java, khóa học lập trình Android, khóa học lập trình C#, các khóa học về lập trình web…Chi tiết các khóa khai giảng xem tại đây. Và còn rất rất nhiều điểm thú vị khác nữa đang chờ bạn khám phá khi tham gia học kinh nghiệm lập trình tại Stanford. Chi tiết xem tại: các chương trình ưu đãi dành cho học viên tại Stanford Hãy liên hệ ngay với chúng tôi theo Hotline: 0866 586 366 – 0963 723 236 hoặc 024 6275 2212 – 024 6662 3355 để được gọi lại tư vấn chi tiết. Sưu tầm và Tổng hợp Nhật Lệ ( Stanford - Nâng tầm tri thức) Tags: học lập trình c++, khóa học lập trình c++