Bạn hay nghe người khác nói “đừng dùng phép toán cộng chuỗi (string concatenation), dùng StringBuilder nhanh hơn”, nhiều người tin ngay, nhưng một số người không tin lắm, vậy làm thế nào để kiểm chứng đây? Có người sẽ nghĩ kế để viết một chương trình dùng “nối chuỗi” một chương trình khác dùng “StringBuilder” để ghép các chuỗi kí tự với nhau, rồi “đếm” xem cái nào chạy nhanh hơn (bằng đồng hồ thường, hoặc một chương trình chạy ngầm để đếm thời gian). Không nhất thiết phải mất thì giờ thế! Hãy thử Profiler xem!
Rất may mắn là nếu bạn cài NetBeans IDE thì Profiler đã có sẵn để dùng. Tạm thời bỏ qua các cắt nghĩa dài dòng về String và StringBuilder, bây giờ chúng ta bắt đầu với thí nghiệm để xem Profiler “làm ăn” thế nào nhé.
Trước hết ta viết một chương trình nhỏ với hai hàm dùng hai kĩ thuật khác nhau badConcat() và useStringBuilder() như sau:
[sourcecode language=”java”] public class StringExperiment {
public static void main(String[] args) {
badConcat();
useStringBuilder();
}
/**
* Dùng phép toán nối chuỗi cộng 1000 lần chuỗi “Profiler is great”,
* rồi xuất ra màn hình
*/
static void badConcat() {
String str = "";
for (int i = 0; i < 1000; i++) {
str += "Profiler is great";
}
System.out.println(str);
}
/**
* Dùng StringBuilder nối 1000 lần chuỗi “Profiler is great”,
* rồi xuất ra màn hình
*/
static void useStringBuilder() {
String str = "";
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 1000; i++) {
sb.append("Profiler is great");
}
System.out.println(sb.toString());
}
}
[/sourcecode]
Để đo xem cái nào nhanh hơn, ta sẽ profile ứng dụng này, với các bước như hình sau đây:
Bước 1: Nhấn nút Profile Main Project
Bước 2: Chọn CPU để bắt đầu phân tích hiệu năng về CPU, tức thời gian thực thi (hai lựa chọn khác là Monitor – theo dõi chi tiết hơn, và Memory – đo đạc các thông số liên quan đến bộ nhớ trong khi ứng dụng thực thi).
Nhấn vào customize, ta có thể tùy chọn việc đo đạc trên lớp nào, hàm nào. Trong trường hợp của ta, cứ để nguyên các lựa chọn mặc định.
Sau khi một số hộp thoại hiện ra (do bạn chạy Profiler lần đầu nên nó cần phải căn chỉnh để kết quả profiling được chính xác, cứ nhân OK nếu bạn không muốn quan tâm gì thêm), bạn có thể đọc kết quả để phân tích.
Bước 3: Đọc kết quả và phân tích
Sau khi profiling xong, bảng kết quả hiện ra với các dữ liệu về thời gian thực thi của từng hàm. Bạn có thể chọn các tab CallTree , Hot Spots và Combined để xem kết quả. Do chương trình của ta ngắn và đơn giản nên danh sách các hàm được gọi rất đơn giản, ta chọn view Combined để xem:
Nhìn vào cửa sổ Hot Spots (các điểm nóng), bạn có thể thấy thời gian thực thi useStringBuilder() hết 0.22 mili giây trong khi badConcat() hết tận 66 ms – chiếm 99.6% thời gian thực thi của toàn bộ chương trình. Có thể thấy giả định đặt ra là đúng.
Ghi chú: bạn có thể thay đổi một số thông số (ví dụ số lần lặp), để xem chương trình sẽ chạy như thế nào, đây cũng là cách thí nghiệm hiệu quả. Thời gian thực thi trên máy của bạn có thể khác xa so với số liệu trong bài này, đừng bận tâm, hãy nhìn vào số liệu bạn nhận được và phân tích.
Tạm kết: khi chương trình của bạn (hoặc của cả nhóm) có dấu hiệu “rùa bò” hơn mức cho phép, ta có thể dùng Profiler để xem chỗ nào đang ngốn CPU nhất. Từ đó phân tích code để tìm ra điểm cải tiến. Đây là cách tiết kiệm thời gian và hiệu quả vì không phải lúc nào bạn cũng có thể giở hết mấy nghìn dòng lệnh để đọc từng dòng được.
Performance là câu chuyện dài kì, và Profiler không chỉ có mỗi cái “võ” là đo thời gian thực thi và tìm hot spots. Nhưng bài này thì dừng ở đây cái đã. Hẹn bạn lần sau, ta lại tiếp tục câu chuyện về performance trong Java nhé. Chúc bạn vui nghề code 😉