Một vài mẹo nho nhỏ để tối ưu hóa cho code của bạn

LAMP Nov 10, 2020

Trong bài viết này mình xin phép chia sẻ một số mẹo nho nhỏ nhằm đáp ứng nhu cầu tối ưu code mà có thể là ai cũng đã biết nhé!

Vậy tối ưu hóa code là gì và vì sao chúng ta nên tối ưu hóa code?
Câu trả lời tối ưu hóa code hay được gọi là optimize code chính là việc áp dụng một số phương pháp hoặc kỹ thuật vào code với mục đích giúp phần mềm :

  • Sử dụng ít tài nguyên hơn.
  • Chạy nhanh hơn.
  • Kích thước chương trình nhỏ hơn.

Để dễ hiểu hơn, hãy cùng mình đi qua một số ví dụ về một số phương pháp optimize hay sử dụng sau đây:

1. Sắp xếp thứ tự về điều kiện trong câu lệnh điều kiện một cách hợp lý

Liệu 2 ví dụ sau có gì khác nhau ?

if (Obj.getValue() === 2 && a === 1) {
  //Do something
}

if (a === 1 && Obj.getValue() === 2) {
  //Do something
}

Nếu xét về kết qủa thì đáp án của 2 ví dụ bên trên hoàn toàn giống nhau đúng không? Tuy nhiên cách mà 2 đoạn code này chạy lại có chút khác nhau đấy.

Ta thấy, Obj.getValue() cần phải mất thời gian gọi hàm ra để lấy được gía trị của object sau đó mới so sánh được với gía trị cần so sánh là 2 vậy thì thời gian để kiểm tra cho điều kiện này sẽ mất nhiều hơn so với việc kiểm tra a === 1.


Chúng ta đều biết false && true = false, false && false = false, true && false = false và true && true mới bắt true
=> chỉ cần có 1 điều kiện là false thì cả câu lệnh if sẽ có kết qủa là false.

  • Nếu chọn cách ở bên trên sẽ có 2 trường hợp xảy ra:
    * Nếu Obj.getValue() === 2 là true vậy sẽ tiếp tục kiểm tra a === 1 => Phải tính cả 2 trường hợp => mất nhiều thời gian
    * Nếu Obj.getValue() === 2 là false thì kết qủa là false => Chỉ mất thời gian để kiểm tra điều kiện đầu tiên
  • Nếu chọn cách bên dưới cũng có 2 trường hợp xảy ra tương tự bên trên:
    * Nếu  a === 1 là true vậy sẽ tiếp tục kiểm tra Obj.getValue() === 2 => Phải tính cả 2 trường hợp => mất nhiều thời gian
    * Nếu a === 1 là false thì kết qủa là false => Chỉ mất thời gian để kiểm tra điều kiện đầu tiên

Thế thì tóm lại nên chọn cách nào hơn? Câu trả lời là tùy vào logic code của bạn, trường hợp nào có khả năng là false nhiều hơn thì chúng ta nên đặt lên trước để khi gặp điều kiện false đầu tiên câu lệnh if sẽ return ngay ra kết quả

Còn nếu như hai điều kiện đều không biết được trường hợp nào sẽ xảy ra nhiều hơn thì chúng ta nên ưu tiên cho cách bên dưới hơn.

2. Sử dụng toán tử ++ và -- hợp lý

Về 2 toán tử này, chúng ta đều biến ++i và --i đều sẽ tăng gía trị lên 1 hoặc gỉam xuống 1 đơn vị rồi trả về gía trị mới của i. Còn i++ và i-- thì sẽ trả về gía trị của i sau đó mới tăng và giảm gía trị. Vậy thì trong 2 cách này, cách nào được tối ưu hơn ?

  1. i++, i--
  2. --i, ++i

Các toán tử ++ và -- khi được đặt ở hậu tố sẽ sinh ra biến trung gian nên sẽ tốn bộ nhớ và thời gian hơn khi phải gọi đến hàm copy constructor và hàm destructor. => Không được tối ưu bằng  
Trong khi đó các toán tử này khi được đặt trước hậu tố thì gía trị của biến sẽ được tăng lên luôn và không cần phải tạo ra biến trung gian. => Tối ưu hơn

3. Sắp xếp biến biến cho class và structure để tối ưu bộ nhớ

Nên sắp xếp các biến thành viên của class/structure từ trên xuống dưới theo chiều giảm dần của kích thước, điều đó sẽ giúp làm giảm kích thước của class và structure.

Ví dụ :

struct {
  bool b;
  double d;
  short s;
  int i;
}

Trường hợp này structure sẽ có kích thước là : 1 (bool) + 7 (padding) + 8 (double) + 2 (short) + 4 (int) + 2 (padding) = 24 bytes.

struct {
  double d;
  int i;
  short s;
  bool b;
}

Còn trường hợp này structure lại có kích thước : 8 (double) + 4 (int) + 2 (short) + 1 (bool) + 1 (padding) = 16 bytes.

Theo ví dụ trên, khi chúng ta sắp xếp biến theo chiều giảm dần thì kích thước bộ nhớ cũng giảm một cách đáng kể.

Có ai thắc mắc padding ở đây là gì không nhỉ? Chúng ta đã biết trình biên dịch thường phân bổ các thành phần dữ liệu riêng lẻ trên các địa chỉ đã được căn chỉnh, nhưng các cấu trúc dữ liệu (data structure) thường có nhiều phần tử dữ liệu thuộc các kiểu dữ liệu khác nhau với các giá trị căn chỉnh (alignment requirement) khác nhau. Trình biên dịch sẽ cố gắng duy trì việc căn chỉnh của các phần tử dữ liệu bằng cách chèn các ô nhớ không sử dụng giữa các phần tử. Kỹ thuật này được gọi là “Padding”.

Trong ví dụ này mình không muốn nói qúa nhiều về padding, nếu các bạn muốn tìm hiểu thêm về cách hoạt động của padding thì hãy tham khảo các nguồn tài nguyên về Data Structure Alignment nhaaa ..... !!!!!!

Để nói về optimize code thì còn nhiều và rộng lắm, thế nên hôm nay mình xin phép đóng góp một vài điều nhỏ nhoi vậy. Mình rất mong nhận được góp ý và sự giúp đỡ của các bạn để giúp mình cải thiện bài viết và đóng góp được nhiều bài viết ý nghĩa hơn nữa.

Cảm ơn các bạn đã theo dõi bài viết, chúc bạn một ngày thật ý nghĩa và rạng ngời nha!

Tags

Great! You've successfully subscribed.
Great! Next, complete checkout for full access.
Welcome back! You've successfully signed in.
Success! Your account is fully activated, you now have access to all content.