1. Trang chủ
  2. » Công Nghệ Thông Tin

TỐI ƯU HÓA XỬ LÝ CHƯƠNG TRÌNH potx

45 412 6
Tài liệu đã được kiểm tra trùng lặp

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Tiêu đề Tối Ưu Hóa Xử Lý Chương Trình
Trường học Trường Đại Học Công Nghệ Thông Tin - Đại Học Quốc Gia Hà Nội
Chuyên ngành Khoa Học Máy Tính
Thể loại Tổng luận
Năm xuất bản 2023
Thành phố Hà Nội
Định dạng
Số trang 45
Dung lượng 423,5 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

Trong chương này, các tác giảtrình bày một số vấn đề về tối ưu hóa xử lý chương trình, trong đó tập trung đisâu phân tích các khía cạnh về tối ưu hóa thời gian xử lý, đồng thời trình bày

Trang 1

1 ĐẶT VẤN ĐỀ 2

2 HIỆN TƯỢNG NÚT CỔ CHAI 4

3 KỸ THUẬT ĐO THỜI GIAN THỰC HIỆN VÀ LƯU LẠI QUÁ TRÌNH HOẠT ĐỘNG (Profiling) 11

3.1 Đo thời gian tự động 11

3.2 Kỹ thuật profiling – lưu lại quá trình thực hiện 13

3.3 Tập trung quan tâm vào các đoạn mã trọng tâm của chương trình 15

3.4 Biểu diễn trực quan số liệu thống kê hiệu năng thực hiện chương trình 16

4 CÁC CHIẾN LƯỢC TỐI ƯU HOÁ THỜI GIAN 17

4.1 Sử dụng thuật toán hoặc cấu trúc dữ liệu tốt hơn 18

4.2 Sử dụng các chức năng tối ưu hóa trình biên dịch 18

4.2 Tinh chỉnh mã nguồn 19

4.4 Không tối ưu hóa những gì không gây vấn đề 21

5 TIN CHỈNH MÃ NGUỒN 22

5.1 Tập hợp những biểu thức chung 22

5.2 Thay thế các thao tác chi phí cao bằng các thao tác chi phí thấp hơn 23

5.3 Trải rộng hay loại bỏ các vòng lặp 23

5.4 Lưu trữ lại các giá trị thường dùng 24

5.5 Xây dựng chức năng cấp phát bộ nhớ đặc dụng 25

5.6 Dùng bộ nhớ trung gian cho việc nhập và xuất dữ liệu 26

5.7 Xử lý riêng từng tình huống đặc biệt 26

5.8 Tính trước kết quả 27

5.9 Dùng các giá trị xấp xỉ 27

5.10 Viết lại mã nguồn bằng ngôn ngữ cấp thấp 27

6 TỐI ƯU HOÁ KHÔNG GIAN LƯU TRỮ 28

6.1 Tiến kiệm không gian bằng cách dùng kiểu dữ kiệu có kích thước nhỏ nhất .29

6.2 Không cần lưu trữ những gì có thể tính lại dễ dàng 29

7 ƯỚC LƯỢNG 31

II NGUYÊN LÝ TRONG REFACTORING 35

1 ĐỊNH NGHĨA REFACTORING 35

2 TẠI SAO NÊN REFACTORING 36

2.1 Refactoring cải thiện thiết kế phần mềm 36

2.2 Refactoring làm phần mềm dễ hiểu 37

2.3 Refactoring giúp tìm Bugs 38

2.4 Refactoring giúp chương trình chạy nhanh hơn 38

3 KHI NÀO THỰC HIỆN REFACTORING 38

3.1 Refactor khi thêm chức năng 39

3.2 Refactor khi cần sửa lỗi (bug) 39

3.3 Refactor khi thực hiện duyệt chương trình 39

4 VẤN ĐỀ VỚI REFACTORING 40

4.1 Cơ sở dữ liệu (Database) 40

4.2 Thay đổi giao diện 41

5 REFACTORING VÀ HIỆU NĂNG XỬ LÝ 41

6 REFACTORING HỖ TRỢ TRONG VISUAL STUDIO 2005 42

Trang 2

Chương 7 I MỘT SỐ VẤN ĐỀ TỐI ƯU HOÁ XỬ LÝ CHƯƠNG TRÌNH

Bài viết này dựa trên nội dung chương 7 “Hiệu năng xử lý chương trình”(Chapter 7 – Performance) trích trong sách “The Practice of Programming” củatác giả Brian W Kernighan va Rob Pike [1999] Trong chương này, các tác giảtrình bày một số vấn đề về tối ưu hóa xử lý chương trình, trong đó tập trung đisâu phân tích các khía cạnh về tối ưu hóa thời gian xử lý, đồng thời trình bàymột số kỹ thuật về tối ưu hóa không gian lưu trữ

1 ĐẶT VẤN ĐỀ

Vấn đề tối ưu hóa xử lý của chương trình được đặt ra từ rất lâu rồi Trướcđây, các nhà lập trình luôn cố gắng tối ưu hóa chương trình do các thế hệ máytính bấy giờ có tốc độ xử lý còn chậm và giá thành cao Ngày nay, máy tính đãtrở nên phổ biến và tốc độ xử lý ngày càng tăng nhanh, do đó nhu cầu đặt ra đốivới bài toán tối ưu hóa tuyệt đối chương trình đã giảm đi rất nhiều Vậy ta cócòn cần quan tâm đến vấn đề hiệu năng xử lý của chương trình nữa hay không?Trên thực tế, bài toán tối ưu hóa hiệu năng xử lý của chương trình vẫn rất có

ý nghĩa trong cuộc sống Tuy nhiên, vấn đề này chỉ thật sự cần được đặc biệtquan tâm khi bài toán cần được giải quyết thật sự có ý nghĩa quan trọng, trongkhi chương trình hiện có để giải quyết bài toán này có tốc độ xử lý còn quáchậm so với yêu cầu thực tế, đồng thời ta có cơ sở để tối ưu hóa việc xử lýnhằm tăng tốc độ của chương trình mà vẫn đảm bảo tính đúng đắn, bền vững vàtrong sáng của chương trình Một chương trình có tốc độ nhanh nhưng đưa rađáp số chưa chính xác không giúp tiết kiệm được thời gian!

Do đó, nguyên lý đầu tiên của tối ưu hóa là phải cân nhắc có cần tối ưu hóachương trình hay không Phải chăng chương trình hiện có đã đủ tốt rồi, khôngcần hoặc không thể tối ưu hóa thêm được nữa? Giả sử ta đã biết được cách màmột chương trình sẽ được sử dụng và môi trường thực hiện chương trình này,liệu việc tối ưu hóa nhằm tăng tốc độ xử lý chương trình có đem lại lợi ích gìhay không Hầu hết những chương trình mà sinh viên viết trong quá trình học ởtrường chỉ được sử dụng một vài lần, sau đó sẽ không sử dụng lại nữa, do đó,vấn đề tốc độ thường không được quan tâm Vấn đề này thường cũng khôngảnh hưởng và không cần quan tâm đối với hầu hềt các chương trình cá nhân,chẳng hạn như các công cụ, khung kiểm tra, thử nghiệm Ngược lại, đối với

Trang 3

các chức năng xử lý chính của một sản phẩm thương mại, chẳng hạn như thưviện đồ họa của phần mềm, vấn đề tối ưu hóa tốc độ xử lý có ý nghĩa hết sứcquan trọng và cần được giải quyết.

Như vậy, khi nào thì ta nên thử tìm cách tăng tốc xử lý chương trình và làmcách nào để thực hiện được điều này? Kết quả cụ thể mà ta mong muốn khi tiếnhành việc tối ưu hóa là gì?

Nội dung chương này sẽ trình bày các vấn đề về làm thế nào để chươngtrình chạy nhanh hơn (tối ưu hóa thời gian) hay sử dụng bộ nhớ tiết kiệm hơn(tối ưu hóa không gian lưu trữ) Tốc độ là vấn đề thường được quan tâm nhiềuhơn nên ta sẽ đi sâu vào vấn đề này Không gian lưu trữ (bộ nhớ chính, đĩa)thường ít được quan tâm hơn, nhưng cũng có ý nghĩa hết sức quan trọng, nên tacũng sẽ tìm hiểu một số vấn đề liên quan đến tối ưu hóa không gian lưu trữ.Như ta đã biết Thuật toán và Cấu trúc Dữ liệu, chiến lược tốt nhất là sử dụngcác thuật toán đơn giản nhất, rõ ràng nhất, và các cấu trúc dữ liệu phù hợp vớibài toán cần giải quyết Do đo, cần đo các thông số hiệu năng hoạt động đểquyết định có cần tiến hành sửa đổi chương trình/thuật toán hay không; cần sửdụng các option của trình biên dịch để phát sinh mã thực hiện có tốc độ xử lýnhanh nhất; cần xác định nhũng phần nào trong chương trình khi được tối ưuhóa sẽ đem lại hiệu quả cao nhất cho toàn bộ chương trình; thực hiện lần lượttừng thay đổi cải tiến rồi sau đó đánh giá, phân tích trước khi tiến hành các thayđổi tiếp theo; đồng thời cần phải giữ lại phiên bản đơn giản chính xác (chưa tối

ưu hóa nhưng chắc chắn chính xác) để kiểm tra kết quả so với các phiên bản cảitiến

Việc đo lường và thống kê là thành phần quan trọng của quy trình cải tiếnhiệu năng chương trình vì suy luận và trực giác của con người có thể dẫn đếnnhững định hướng sai lầm và cần phải được bổ sung bằng những công cụ đothời gian thực hiện và lập sơ đồ thời gian của chương trình Dựa vào các số liệu

đo đạt và thống kê được thông qua các kỹ thuật như đo thời gian (timingcommand) và lưu lại quá trình hoạt động (profiler), ta có thể rút ra được nhữngnhận xét và giải pháp nhằm tối ưu hóa chương trình Việc cải tiến hiệu năngphải đi kèm với quá trình kiểm chứng chương trình (sử dụng kỹ thuật kiểm tra

tự động, lưu vết các sửa đổi và phiên bản, thanh tra mã nguồn – code inspection,

sử dụng các bộ dữ liệu thử nghiệm ) để đảm bảo chương trình sau khi sửa đổivẫn đảm bảo tính đúng đắn và không làm mất đi các ưu điểm vốn có trong cácphiên bản trước đó

Trang 4

Nếu từ ban đầu chương trình được viết tốt với thuật toán hiệu quả thì có thểchỉ cần sửa đổi rất ít hoặc thậm chí không cần sửa đổi chương trình để cải tiếnhiệu năng Ngược lại, đối với những chương trình viết chưa tốt, tổ chức chưahợp lý, không trong sáng, việc tối ưu hóa đòi hỏi phải sửa đổi rất nhiều, thậmchí phải tổ chức lại cấu trúc chương trình và viết lại từ đầu.

2 HIỆN TƯỢNG NÚT CỔ CHAI

Đầu tiên, ta mô tả cách giải quyết hiện tượng nút cổ chai trong một chươngtrình quan trọng được sử dụng thường xuyên trong môi trường cục bộ

Các thư điện tử mà ta nhận được thông qua thiết bị gateway nối kết giữamạng cục bộ với Internet Mỗi ngày, có hàng vạn thư điện tử từ bên ngoài đượcgởi đến cho vài nghìn thành viên trong mạng cục bộ thông qua gateway và sau

đó được chuyển đến từng người trong mạng nội bộ Sự ngăn cách này cô lậpmạng nội bộ với Internet và cho phép chỉ cần công bố một tên máy (là tên củagateway) cho tất cả mọi thành viên trong mạng nội bộ

Một trong số các dịch vụ gateway là lọc các “spam”, là các thư rác kèm

theo các quảng cáo về những dịch vụ mà lợi ích chưa được kiểm chứng Sau

thời gian thử nghiệm ban đầu thành công, bộ lọc các “spam” được chính thức

cài đặt và sử dụng như đặc tính không thể thiếu cho tất cả người dùng trongmạng nội bộ, và rồi rắc rối lập tức xuất hiện Gateway, vốn cũ kỹ và thường rấtbận, bị quá tải vì chương trình lọc chiếm quá nhiều thời gian – nhiều hơn hẳn sovới thời gian cần thiết cho tất cả các thao tác xử lý khác đối với bức thư – đếnmức độ hàng đợi thư bị đầy và việc truyền phát thư tín bị trì hoãn nhiều giờtrong khi hệ thống cố xoay sở để kịp phân phối thư

Trên đây là một ví dụ về vấn đề tốc độ thực hiện chương trình: chương trìnhkhông đủ nhanh để hoàn thành nhiệm vụ, và sự chậm trễ này tạo ra trở ngại chongười dùng Do đó, chương trình cần phải được cải tiến, tối ưu hóa để có thểchạy nhanh hơn nhiều so với phiên bản hiện tại

Trước hết, ta hãy khảo sát cách hoạt động của bộ lọc “spam” Mỗi thông

điệp gửi tới được xem như một chuỗi ký tự đơn, và một bộ so mẫu ký tự kiểmtra chuỗi đó xem có chứa bất kỳ một cụm từ nào trong số các cụm từ thườnggặp trong các “spam” hay không, chẳng hạn như: “Make millions in your sparetime” (kiếm hàng triệu đồng trong thời gian rảnh của bạn) hay “XXX-rated”(các trang khiêu dâm) Các thông điệp có khuynh hướng lặp đi lặp lại, do đó, kỹ

thuật này có hiệu quả đáng kể, và nếu như một thông điệp “spam” lọt lưới thì

Trang 5

một cụm từ đặc trưng cho “spam” đó sẽ được thêm vào danh sách các “spam”

để chặn nó vào lần sau

Do không có sẵn một công cụ so sánh chuỗi vừa chạy nhanh vừa đáng tin

cậy, ví dụ như grep, nên người ta viết ra một bộ lọc riêng dùng cho mục đích lọc các “spam” Mã nguồn rất đơn giản; chương trình lọc “spam” sẽ tìm xem

mỗi bức thông điệp có chứa một trong số các cụm từ (các mẫu) nào đó haykhông:

/* Hàm isspam:

kiểm tra chuỗi thông điệp mesg có chứa spam nào không */

int isspam(char *mesg)

{

int i;

for (i=0; i<npat; i++)

if (strstr(mesg, pat[i]) != NULL){

printf("spam: match for '%s'\n", pat[i]);

}}

Làm thế nào ta có thể thực hiện đoạn chương trình trên nhanh hơn? Ta cầnphải tìm kiếm chuỗi ký tự mẫu trong bức thông điệp, do đó, việc sử dụng hàm

strstr của thư viện C là cách tốt nhất để tìm kiếm vì đây là hàm thư viện chuẩnđược xây dựng hiệu quả

Sử dụng kỹ thuật lưu lại quá trình hoạt động (kỹ thuật profiling - sẽ đượctrình bày chi tiết trong phân sau Kỹ thuật profiling – lưu lại quá trình thựchiện.), ta nhận thấy rằng hàm strstr có một số vấn đề chưa phù hợp khi sử dụng

cho một bộ lọc spam Trong trường hợp cụ thể này, việc thay đổi cách thức làm

việc của hàm strstr có thể tăng hiệu quả hoạt động của hệ thống Hàm strstr đượccài đặt lại như sau:

/* Hàm strstr :

dùng hàm strchr để tìm kiếm kí tự đầu tiên */

char* strstr(const char *s1, const char *s2)

{

int n;

Trang 6

Hiện tượng trên có thể được lý giải bằng các lý do chính sau đây Trướctiên, hàm strncmp lấy chiều dài chuỗi mẫu bằng strlen làm tham số đầu vào Thếnhưng vì chuỗi mẫu có chiều dài cố định nên việc tính lại độ dài chuỗi mẫu khi

xử lý mỗi thông điệp là không cần thiết

Thứ hai, hàm strncmp có chứa một vòng lặp phức tạp Thực tế, không những

hệ thống phải so sánh từng byte của hai chuỗi mà phải tìm byte cuối ‘\0’ trên cảhai chuỗi trong khi vẫn đếm lùi tham số chiều dài Vì chiều dài của tất cả cácchuỗi đều đã biết trước (dù không cần dùng tới hàm strncmp) nên sự phức tạpnày là không cần thiết Ta thấy rằng phép đếm là cần thiết, nhưng việc kiểm tra

byte ‘\0’ sẽ lãng phí nhiều thời gian

Thứ ba, hàm strnchr cũng phức tạp, bởi vì đồng thời vừa tìm ký tự và kiểm

tra byte ‘\0’ kết thúc bức thông điệp Trong một lần gọi hàm isspam, bức thông

điệp là cố định, vì vậy thời gian dùng để kiểm tra byte ‘\0’ là lãng phí vì ta đãbiết chính xác bức thông điệp kết thúc ở đâu

Trang 7

Cuối cùng, dù cho hàm strncmp, strchr, và strlen đều rất hiệu quả khi làm việcđộc lập, tổng thời gian cần để gọi các hàm này cũng xấp xỉ với thời gian tínhtoán của chúng Sẽ hiệu quả hơn nếu làm mọi việc bằng chỉ một hàm strstr đượcviết lại thật cẩn thận và tránh gọi tất cả những hàm khác.

Những vấn đề thuộc dạng này chính là một nguồn gốc chung làm chậm tốc

độ thực hiện chương trình – một thủ tục hoặc một phương thức giao tiếp làmviệc tốt trong một tình huống điển hình nhưng lại thực hiện kém hiệu quả trongtình huống bất thường xảy ra trở thành vấn đề trung tâm của chương trình Hàm

strstr có sẵn thực hiện tốt khi chuỗi mẫu và chuỗi cần tìm ngắn và thay đổi ởmỗi lần hàm được gọi Nhưng khi chuỗi cần tìm dài và cố định thì thời gian thờigian xử lý lại bị lãng phí quá nhiều

Từ những nhận xét trên đây, ta quyết định viết lại hàm strstr để xử lý trênchuỗi mẫu cùng với chuỗi thông điệp nhằm tìm ra chỗ so khớp mà không cầngọi các thủ tục con Khả năng thực hiện khi thực hiện giải pháp này hoàn toàn

có thể dự đoán được: chương trình có thể hơi chậm trong một số trường hợp cá

biệt, nhưng lại rất nhanh trong việc lọc các “spam” và quan trọng nhất là không

bao giờ chạy quá lâu Để kiểm tra lại tính đúng đắn của bản cài đặt mới cũngnhư tốc độ thực hiện của chương trình mới, ta xây dựng một bộ kiểm chứng tốc

độ thực hiện Bộ thử này không chỉ gồm các ví dụ đơn giản như tìm một từtrong câu, mà còn gồm cả một số trường hợp đặc biệt, ví dụ như tìm chuỗi mẫuchỉ có một ký tự ‘x’ trong chuỗi có một ngàn ký tự ‘e’, và chuỗi mẫu có mộtngàn ký tự ‘x’ trong một chuỗi chỉ có một ký tự ‘e’ Những trường hợp đặc biệtnhư vậy là phần chính trong việc đánh giá khả năng thực hiện

Thư viện được cập nhật bằng hàm strstr mới và bộ lọc “spam” chạy nhanh

hơn 30%, đây là một kết quả cải tiến đáng kể cho việc viết lại

Tuy nhiên, tốc độ thực hiện vẫn còn quá chậm Khi giải quyết các khó khăn,điều quan trọng là xác định đúng vấn đề cần giải quyết Cho đến nay, ta đangđặt vấn đề tìm cách nhanh nhất để truy soát một chuỗi ký tự mẫu trong mộtchuỗi ký tự Tuy nhiên, thật ra thì vấn đề là tìm kiếm một tập hợp lớn, cố địnhcác chuỗi ký tự mẫu trong một chuỗi ký tự dài thay đổi Trong trường hợp đó,hàm strstr chưa thật sự là giải pháp đúng

Cách hiệu quả nhất để làm cho một chương trình chạy nhanh hơn là dùngmột giải thuật tốt hơn Bây giờ, khi đã nhìn rõ hơn vấn đề cần giải quyết, ta cầnsuy nghĩ xem thuật toán nào sẽ làm việc tốt nhất

Trang 8

Xét vòng lặp cơ bản:

for (i=0; i < npat; i++)

if (strstr(meg, pat[i]) != NULL)

return 1;

Vòng lặp này duyệt qua bức thông điệp npat lần độc lập với nhau; giả sửđoạn lệnh không tìm ra bất kỳ sự so khớp nào, đoạn lệnh này đã phân tích từng

byte của bức thông điệp npat lần trongstrlen(mesg)*npat phép so sánh

Một cách tiếp cận tốt hơn là đảo ngược vòng lặp, quét qua bức thông điệpmột lần ở vòng lặp ngoài trong khi tìm tất cả các chuỗi mẫu song song ở vònglặp trong:

for (j=0; mesg[j] != '\0'; j++)

if (có chuỗi mẫu nào có phần đầu trùng với

ký tự đầu củamesg[j])

return 1;

Sự cải thiện tốc độ bắt nguồn từ cách nhìn hết sức đơn giản Để nhận ra liệu

có chuỗi mẫu nào so khớp với bức thông điệp ở vị trí j không, ta không cần phảixét tất cả các chuỗi mẫu mà chỉ cần xét các chuỗi có cùng ký tự đầu tiên với

mesg[j] Nói cách khác, với 52 ký tự chữ hoa và chữ thường, ta chỉ cần thực hiện

strlen(mesg)*npat/52 phép so sánh Vì các chữ cái không phân bố đều, có nhiều

từ bắt đầu bằng ký tự ‘s’ hơn là bằng ký tự ‘x’, ta không thể kết luận rằng giải

pháp này cải thiện tốc độ nhanh hơn gấp 52 lần phiên bản trước, tuy nhiên, rõràng việc tối ưu hóa này đem lại kết quả rất đáng kể Để thực hiện, ta xây dựngmột bảng băm dùng ký tự đầu tiên của chuỗi mẫu làm khóa

Dựa vào một vài tính toán trước để xây dựng một bảng những chuỗi mẫu bắtđầu với từng ký tự, hàm isspam vẫn được viết ngắn gọn như sau:

int patlen[NPAT];

/* mảng chiều dài của các chuỗi mẫu */

int starting[UCHAR_MAX+1][NSTART];

/* danh sách các chuỗi mẫu bắt bằng ký tự tương ứng */

int nstarting[UCHAR_MAX+1];

/* số chuỗi mẫu bắt đầu bằng ký tự tương ứng */

Trang 9

/* Hàm isspam: kiểm tra chuỗi thông điệp mesg có chứa spam nào không */

int isspam(char *mesg)

}

return 0;

}

Với mỗi ký tự ‘c’, mảng hai chiều starting[c][] chứa danh sách các chuỗi mẫu

bắt đầu bằng ký tự ‘c’ Mảng nstarting[c] ghi nhận bao nhiêu chuỗi mẫu bắt đầu

bằng ký tự ‘c’ Nếu không có các bảng đó, vòng lặp trong sẽ chạy từ 0 đến npat,khoảng 1000, thay vì chỉ chạy từ 0 đến khoảng 20 Còn phần tử mảng patlen[k]

chứa kết quả tính toán trước của strlen(pat[k]).

Hình dưới đây phác họa các cấu trúc dữ liệu trên dùng một tập hợp ba chuỗi

mẫu bắt đầu bằng ký tự ‘b’:

Trang 10

để lưu trữ thông tin của các chuỗi ký tự mẫu

Dưới đây là đoạn chương trình để xây dựng các bảng chứa thông tin cácchuỗi mẫu:

Phụ thuộc vào dữ liệu nhập, bộ lọc “spam” bây giờ cải tiến chạy nhanh hơn

từ 5 đến 10 lần khi dùng hàm strstr, và nhanh hơn từ 7 đến 15 lần khi dùngphương pháp đầu tiên Tốc độ thực hiện không thể đạt được mức nhanh hơn 52

Trang 11

lần so với phiên bản đầu tiên, một phần do sự phân bố không đều của bảng chữcái, một phần do vòng lặp trong chương trình mới phức tạp hơn, một phần khác

do vẫn còn phải thực hiện quá nhiều phép so chuỗi không đạt, nhưng bộ lọc

“spam” không gây ra hiện tượng nút cổ chai gây tắt nghẽn việc phân phối thư

nữa Vấn đề tốc độ thực hiện chương trình đã được giải quyết

Phần còn lại của chương này sẽ đi sâu vào các kỹ thuật được dùng để pháthiện các vấn đề về tốc độ thực hiện chương trình, xác định các đoạn mã chậm

và tăng tốc cho chúng Trước khi tiếp tục, ta cần xem lại ví dụ về bộ lọc

“spam” nhằm rút ra những bài học cần thiết Nếu bộ lọc “spam” không phải là

một nút cổ chai thì tất cả các cố gắng mà ta vừa thực hiện đều trở nên không

còn ý nghĩa Một khi đã xác định được vấn đề, ta sử dụng kỹ thuật profiling và

những kỹ thuật khác để khảo sát và phân tích việc thực hiện của chương trìnhnhằm tìm ra mấu chốt vấn đề thật sự ở đâu Sau đó, ta phải chắc chắn rằng ta đãgiải quyết đúng vấn đề, thử nghiệm toàn bộ chương trình chứ không chỉ tậptrung vào hàm strstr, là đầu mối nghi ngờ ban đầu, thoạt đầu tưởng là đã rõnhưng thực ra lại là không đúng Cuối cùng, ta giải quyết đúng vấn đề bằng mộtgiải thuật tốt hơn, và kiểm nghiệm lại xem chương trình đã chạy nhanh hơnchưa Một khi chương trình đã chạy đủ nhanh, ta sẽ dừng lại Việc suy nghĩ tìmcách cải tiến tiếp tục là không cần thiết?

3 KỸ THUẬT ĐO THỜI GIAN THỰC HIỆN VÀ LƯU LẠI QUÁ TRÌNH HOẠT ĐỘNG (Profiling)

3.1 Đo thời gian tự động

Đa số hệ thống đều có lệnh để đo thời gian chạy một chương trình TrênUnix, lệnh này là time:

Trang 12

- Thời gian “thực” (real time) là tổng thời gian từ khi bắt đầu đến khi kếtthúc chương trình;

- Thời gian sử dụng CPU ở chế độ người dùng (user mode) là thời giandùng để thực hiện chương trình;

- Thời gian CPU ở chế độ hệ thống (system mode) là thời gian hệ điềuhành xử lý theo yêu cầu của chương trình

Nếu hệ thống bạn đang dùng có lệnh tương tự, hãy dùng lệnh đó Giá trị đođược chứa đựng nhiều thông tin hơn, tin cậy hơn, và dễ theo dõi hơn là thờigian đo bằng một đồng hồ bấm giờ Cần lưu ý là bạn hãy ghi chú thật cẩn thận.Trong khi bạn làm việc trên chương trình, sửa đổi, đo đạc, bạn sẽ thu được rấtnhiều thông tin đến mức chỉ cần sau một vài ngày bạn sẽ bị nhầm lẫn các số liệu

có được (chẳng hạn như phiên bản nào của chương trình chạy nhanh hơn20%?) Nhiều kỹ thuật đã nghiên cứu trong Chương 6 có thể được đưa vào để

đo đạc và cải tiến tốc độ thực hiện của chương trình Bạn nên cho chương trìnhthực thi thật sự trên máy tính và đo đạt các số liệu với các bộ dữ liệu kiểmchứng, và điều quan trọng nhất là dùng kỹ thuật kiểm tra hồi quy để bảo đảmcác sửa đổi không làm mất đi tính đúng đắn của chương trình

Nếu hệ thống của bạn không có lệnh time, hay nếu bạn đang đo thời gian củamột hàm cụ thể nào đó, bạn có thể dễ dàng xây dựng một cấu trúc đo thời giantương tự Trong C và C++ đều có cung cấp một hàm chuẩn, hàm clock, dùng đểtính thời gian CPU mà chương trình đã dùng cho đến thời điểm hiện tại Hàmnày có thể được gọi trước và sau một hàm để đo thời gian sử dụng CPU:

elapsed = clock() - before;

printf("function used %.3f seconds\n",

elapsed/CLOCKS_PER_SEC);

Trang 13

Hằng số CLOCKS_PER_SEC xác định số lần dao động của bộ đếm (timer)

hệ thống trong 1 giây Trong trường hợp hàm thực hiện trong một phần rất nhỏcủa một giây, ta có thể cho thực hiện nhiều lần hàm này bằng một vòng lặp, tuynhiên, khi đó, ta cần lưu ý đến chi phí của bản thân vòng lặp nếu thời gian nàyđáng kể so với tổng thời gian thực hiện của hàm cần đo:

before = clock();

for (i=0; i<1000; i++)

short_running_function();

elapsed = (clock() - before)/(double)i;

Trong Java, ta sử dụng các hàm trong lớp Date để xấp xỉ thời gian CPU:

Date before = new Date();

long_running_function();

Date after = new Date();

long elapsed = after.getTime() - before.getTime();

Hàm getTime trả về giá trị tính bằng miligiây

3.2 Kỹ thuật profiling – lưu lại quá trình thực hiện

Bên cạnh phương pháp đo thời gian đã trình bày ở trên, ta còn có một công

cụ quan trọng hỗ trợ phân tích việc thực thi chương trình: đó chính là kỹ thuậtprofiling - một hệ thống giúp lưu lại thông tin quá trình thực hiện Kỹ thuật nàygiúp ghi nhận lại việc gọi thực hiện và thời gian thực hiện từng thao tác trongchương trình Một số hệ thống ghi nhận chi tiết từng hàm, số lần mà hàm nàyđược gọi thực hiện và tỷ lệ thời gian đã sử dụng để thực hiện từng hàm so vớitoàn bộ thời gian thực hiện đoạn chương trình Một số hệ thống ghi nhận lại sốlần từng phát biểu trong chương trình được thực hiện Những phát biểu đượcthực hiện nhiều lần sẽ chiếm phần lớn thời gian thi hành, trong khi đó, nhữngphát biểu không bao giờ được thực hiện chính là những đoạn mã thừa hoặc chưađược kiểm tra đầy đủ

Kỹ thuật ghi nhận quá trình thực hiện là công cụ hiệu quả để tìm các đoạn

mã chính trọng tâm của chương trình, tức là những hàm hoặc những đoạn mãchiếm phần lớn thời gian tính toán Tuy nhiên, việc sử dụng và phân tích các sốliệu kết quả của kỹ thuật này cần được tiến hành một cách thận trọng Do tínhchất phức tạp của trình biên dịch cũng như trong các hiệu ứng bộ nhớ đệm và

bộ nhớ chính, cùng với việc ghi nhận quá trình thực hiện của chương trình sẽ

Trang 14

làm ảnh hưởng đến tốc độ thực hiện của chương trình này nên các thống kê của

kỹ thuật này chỉ là kết quả xấp xỉ

Kỹ thuật ghi nhận quá trình thực hiện thường được kích hoạt bằng một cờcủa trình biên dịch hoặc chức năng đặc biệt Chương trình được cho thực hiện,

và sau đó một công cụ phân tích sẽ biểu diễn các kết quả Trên Unix, ta thường

sử dụng cờ -p và công cụ prof như sau:

% cc –p spamtest.c –o spamtest

% spamtest

% prof spamtest

Bảng sau đây thể hiện kết quả ghi nhận quá trình thực hiện chương trình bộ

lọc spam Chương trình dùng một bức thông điệp cố định và một tập hợp cố

định gồm 217 cụm từ mẫu, tập hợp này so khớp với bức thông điệp 10000 lần.Chương trình chạy trên máy 250 MHz MIPS R1000 dùng bản gốc của hàm

strstr trong đó gọi các hàm chuẩn khác Cần chú ý sự xuất hiện các giá trị kích

cỡ của dữ liệu đầu vào (217 cụm từ) và số lần chạy (10000) trong cột số lần gọithực hiện

1.825 3.3 99.8 456225559 344882213 2170435 strlen

0.088 0.2 100.0 21950000 28510000 10000 isspam0.000 0.0 100.0 100025 100028 1 main

0.000 0.0 100.0 53677 80268 219 _memcopy0.000 0.0 100.0 48888 46403 217 strcpy

0.000 0.0 100.0 17989 19894 219 fgets

0.000 0.0 100.0 16798 17547 230 malloc0.000 0.0 100.0 10305 10900 204 realfree0.000 0.0 100.0 6293 7161 217 estrdup0.000 0.0 100.0 6032 8575 231 cleanfree0.000 0.0 100.0 5932 5729 1 readpat0.000 0.0 100.0 5899 6339 219 getline0.000 0.0 100.0 5500 5720 220 _malloc

Trang 15

Bảng 1: Bảng thống kê quá trình thực hiện chương trình spamtest nguyên thủy

Rõ ràng hàm strchr và hàm strncmp, cả hai do hàm strstr gọi, chiếm hầu hết

thời gian thực hiện chương trình Nhận xét của tác giả Knuth hoàn toàn chínhxác: chỉ một phần nhỏ của chương trình đã chiếm gần hết thời gian chạy

chương trình Khi một chương trình lần đầu tiên được xây dựng profile, hàm

được gọi nhiều nhất thường chiếm đến 50% hoặc hơn thời gian thực hiệnchương trình, như ở trường hợp này Điều này.giúp ta dễ dàng xác định cần tậptrung chú ý vào phần nào trong chương trình để cải tiến việc thực hiện

3.3 Tập trung quan tâm vào các đoạn mã trọng tâm của chương trình

Sau khi viết lại hàm strstr, ta ghi nhận lại quá trình thực hiện của chươngtrình spamtest Lúc này, ta nhận thấy rằng 99.8% thời gian bây giờ bị chiếm bởihàm strstr, mặc dù cả chương trình đã nhanh hơn rõ rệt Khi gặp tình trạng códuy nhất một hàm gây ra hiện tượng nút cổ chai ta thường có hai con đường đểchọn lựa: cải tiến hàm đó bằng một thuật toán tốt hơn, hoặc bỏ toàn bộ hàm đóbằng cách viết lại cả chương trình

Trong trường hợp này, ta chọn giải pháp viết lại toàn bộ chương trình Dướiđây là một vài dòng kết quả đầu tiên của việc ghi nhận quá trình thực hiện củachương trình spamtest dùng bản cài đặt có tốc độ cao của hàm isspam Cần chú ýrằng tổng thời gian toàn bộ đã giảm đi rất nhiều, trong đó hàm memcmp là hàm

được gọi xử lý nhiều nhất (hot spot) và hàm isspam bây giờ chiếm một phầnđáng kể trong thời gian tính toán Phiên bản này phức tạp hơn so với phiên bản

sử dụng hàm strstr nhưng ít tốn chi phí hơn nhờ không sử dụng hàm strlen và

strchr trong hàm isspam và việc thay thế hàm strncmp bằng hàm memcmp có chi

phí xử lý đối với từng byte thấp hơn.

Giây % cum% Số chu kỳ Số lệnh số lần gọi Hàm3.524 56.9 56.9 880890000 1027590000 46180000 memcmp2.662 43.0 100.0 665550000 902920000 10000 isspam

0.001 0.0 100.0 140304 106043 652 strlen

0.000 0.0 100.0 100025 100028 1 main

Bảng 2: Bảng thống kê quá trình thực hiện

chương trình spamtest cải tiến

Hãy so sánh số chu kỳ đếm được và số lần gọi trong hai kết quả thống kêquá trình thực hiện chương trình Cần lưu ý rằng số lần gọi hàm strlen đã giảm

Trang 16

từ vài triệu lần gọi xuống còn 652 lần, số lần gọi hàm strncmp bằng với số lầngọi hàm memcmp (có chi phí xử lý đối với từng byte thấp hơn) Cũng cần lưu ý

là hàm isspam sau khi tích hợp hàm strchr vẫn sử dụng số chu kỳ ít hơn nhiều sovới hàm strchr trước đó vì hàm này chỉ kiểm tra các chuỗi mẫu thích hợp ở mỗi

bước

Một đoạn lệnh khi thực hiện chiếm phần lớn thời gian xử lý của toàn bộchương trình, tạm gọi là điểm nóng (hot spot), có thể được loại bỏ hay “làmnguội” đi bằng một số kỹ thuật đơn giản hơn so với cách ta đã dùng cho chương

trình bộ lọc spam Xét ứng dụng Awk, kết quả ghi nhận cho thấy một hàm được

gọi thực hiện đến hàng triệu lần trong vòng lặp sau đây:

for (j=i; j < MAXFLD; j++)

clear(j);

Vòng lặp này, thực hiện việc xóa các trường trước khi đọc vào một dòngmới, đã chiếm hơn 50% thời gian thi hành Hằng số MAXFLD (số trường tối đacủa một dòng) bằng 200 Tuy nhiên, trong hầu hết các ứng dụng Awk, sốtrường thực sự được sử dụng và cần được xóa chỉ gồm hai đến ba trường Dovậy, rất nhiều thời gian bị lãng phí vào việc xóa các trường không bao giờ đượcxác lập Khi thay hằng số trên bằng giá trị số lượng tối đa các trường trong lầnthực hiện trước đó cho phép tăng tốc toàn bộ chương trình lên khoảng 25%.Chúng ta chỉ cần thay đổi giá trị cận trên của vòng lặp:

for (j=i; j < maxfld; j++)

clear(j);

maxfld = i

3.4 Biểu diễn trực quan số liệu thống kê hiệu năng thực hiện chương trình

Hình vẽ thường rất hữu ích trong việc thể hiện trực quan các số liệu thống

kê hiệu năng thực hiện của chương trình Các hình vẽ có khả năng biểu diễntrực quan thông tin về hiệu quả của việc thay đổi các tham số, so sánh các thuậttoán và các cấu trúc dữ liệu, và đôi khi còn chỉ ra được những trường hợpchương trình thực hiện theo cách không mong muốn

Đồ thị dưới đây thể hiệu ảnh hưởng kích thước mảng các bảng băm lên thời

gian thi hành chương trình giải thuật Markov (viết bằng C) với dữ liệu đầu vào

gồm 42685 từ và 22482 tiếp đầu ngữ Ta hãy làm hai thử nghiệm Một thử

Trang 17

nghiệm gồm một số các lần chạy chương trình dùng các mảng có kích thước làlũy thừa của 2 từ 2 đến 16384; thử nghiệm kia dùng các mảng có kích thước là

số nguyên tố lớn nhất không vượt quá lũy thừa của 2 gần nhất Ta xem liệu kíchthước mảng là số nguyên tố có tạo ra sự khác biệt nào trong tốc độ thực hiệnchương trình hay không

Hình 2: Đồ thị thể hiện sự biến thiên tốc độ xử lý của chương trình với kích thước bảng băm trong trường hợp kích thước là lũy thừa của 2 và trường

hợp kích thước là số nguyênt tố

Đồ thị trên cho thấy thời gian thực hiện của chương trình gần như khôngthay đổi đối với kích thước bảng băm lớn hơn hay bằng 1000, đồng thời kíchthước bảng băm là lũy thừa của 2 hay là số nguyên tố không phải là yếu tố ảnhhưởng đến tốc độ thực hiện chương trình

4 CÁC CHIẾN LƯỢC TỐI ƯU HOÁ THỜI GIAN

Trước khi bắt đầu sửa đổi một chương trình để tăng tốc độ xử lý nhanh hơn,hãy chắc rằng chương trình hiện tại chạy thật sự quá chậm, và hãy dùng cáccông cụ đo thời gian và công cụ ghi nhận quá trình thực hiện để xác định đượcphần lớn thời gian xử lý của chương trình làm những công việc gì Một khi đãbiết xác định được vấn đề, ta có nhiều áp dụng nhiều chiến lược để thực hiệnmục đích tối ưu hóa thời gian thực hiện Dưới đây là một số chiến lược nhằm tối

ưu hóa thời gian thực hiện theo thứ tự hiệu quả giảm dần

5020105

12

Kích thước bảng băm

0.50.2

Thời gian

(giây)

Số nguyên tố Lũy thừa của 2

Trang 18

4.1 Sử dụng thuật toán hoặc cấu trúc dữ liệu tốt hơn

Yếu tố quan trọng nhất làm cho chương trình chạy nhanh hơn là lựa chọnthuật toán và cấu trúc dữ liệu hiệu quả Trên thực tế, có sự khác biệt rất lớn giữamột thuật toán hiệu quả và một thuật toán không hiệu quả Như đã trình bày

trên - 2 , đối với chương trình bộ lọc spam, việc thay đổi cấu trúc dữ liệu giúp

cải thiện tốc độ nhanh hơn 10 lần, và hệ số tốc độ này còn có thể được cải thiện

lớn hơn nếu như thuật toán có độ phức tạp giảm từ O(n2) còn O(n logn)

Vấn đề xác định độ phức tạp thuật toán cũng như chương trình là vấn đề khá

phức tạp Đoạn lệnh duyệt 1 chuỗi ký tự s dưới đây dường như có độ phức tạp tuyến tính nhưng thật ra độ phức tạp thuật toán này lại là bậc 2 (O(n2)) Nếu

chuỗi s có n ký tự, mỗi lần gọi hàm strlen sẽ thực hiện việc duyệt qua n ký tự của chuỗi, trong khi vòng lặp được thực hiện n lần.

? for (i = 0; i < strlen(s); i++)

? if (s[i] == c)

4.2 Sử dụng các chức năng tối ưu hóa trình biên dịch

Chúng ta có thể cải thiện đáng kể tốc độ xử lý chương trình một cách đơngiản mà không cần sửa đổi bất kỳ một dòng mã nguồn nào bằng cách sử dụnghiệu quả các chức năng tối ưu hóa có sẵn trong trình biên dịch Các trình biêndịch hiện đại ngày nay có khả năng tối ưu hóa hiệu quả các đoạn mã nguồnchương trình

Việc sử dụng các chiến lược tối ưu hóa trình biên dịch có khuynh hướng gâyxáo trộn việc bắt lỗi (debug) mã nguồn Do đó, ở chế độ mặc định, các trìnhbiên dịch C và C++ thường không sử dụng nhiều các chức năng tối ưu hóa chochương trình Các tùy chọn trong trình biên dịch cho phép lập trình viên quyếtđịnh sử dụng hay không các chức năng tối ưu hóa của trình biên dịch Lập trìnhviên thường cần phải kích thước tường minh tùy chọn tối ưu hóa mã nguồn củatrình biên dịch sau khi đã kiểm lỗi xong chương trình

Việc tối ưu hóa thông qua chức năng trình biên dịch thường cải thiện thờigian chạy chương trình từ vài phần trăm cho đến hai trăm phần trăm Tuy nhiên,việc tối ưu hóa này đôi khi lại có thể làm giảm tốc độ chương trình, do vậy cần

đo lường sự cải thiện trước khi đóng gói sản phẩm Đối với chương trình bộ lọc

spam, với cùng dữ liệu thử nghiệm, chương trình sử dụng phiên bản thuật toán

Trang 19

so trùng khớp cuối cùng có thời gian thi hành ban đầu là 8.1 giây giảm xuốngcòn 5.9 giây khi sử dụng chức năng tối ưu hóa của trình biên dịch (mức độ cảithiện là 25%) Ngược lại, ở phiên bản dùng hàm strstr đã sửa đổi, việc tối ưu hóakhông đem lại một cải thiện nào bởi lẽ hàm strstr đã được tối ưu hóa khi đưa vàothư viện: bộ tối ưu hóa chỉ áp dụng vào mã nguồn đang được biên dịch trongchương trình chứ không phải vào các thư viện hệ thống Tuy nhiên, một số trìnhbiên dịch có các bộ tối ưu hóa toàn cục có khả năng phân tích toàn bộ chươngtrình tìm những chỗ còn có thể cải thiện được Nếu một trình biên dịch như thế

có trong hệ thống của bạn, hãy thử sử dụng; điều này có thể giúp giảm đượcmột vài chu kỳ xử lý

Một điều cần phải hiểu rõ là càng cho phép trình biên dịch tối ưu hóa nhiềubao nhiêu thì khả năng đưa vào lỗi trong chương trình càng nhiều bấy nhiêu.Sau khi sử dụng chức năng tối ưu hóa của trình biên dịch, bạn cần sử dụng các

bộ dữ liệu thử nghiệm để kiểm soát việc tối ưu hóa này không làm mất đi tínhđúng đắn của chương trình

4.2 Tinh chỉnh mã nguồn

Chọn lựa thuật toán thích hợp và hiệu quả là điều rất quan trọng khi kíchthước dữ liệu lớn Hơn thế nữa, việc cải thiện do thuật toán có tác dụng trên mọimáy, mọi trình biên dịch, mọi ngôn ngữ lập trình Nhưng trong trường hợp đã

có thuật toán đúng mà tốc độ vẫn còn là vấn đề cần giải quyết, bạn nên thử tinhchỉnh mã nguồn: điều chỉnh chi tiết các vòng lặp và phát biểu sao cho tốc độthực hiện nhanh hơn

Phiên bản isspam đã xét ở cuối phần -2 chưa được tinh chỉnh Chúng ta sẽtiến hành “trau chuốt” đoạn mã nguồn chương trình Dưới đây là đoạn mãnguồn trước khi cải tiến:

Trang 20

return 1;

}}

}

Phiên bản ban đầu này với bộ dữ liệu thử nghiệm chọn trước thực hiện trong6.6 giây (khi đã sử dụng bộ tối ưu hóa trình biên dịch) Vòng lặp trong có mộtchỉ số mảng (nstarting[c]) trong điều kiện lặp, mà giá trị của chỉ số này khôngđổi ở mỗi lần lặp của vòng lặp ngoài Ta có thể tránh tính lại giá trị đó bằngcách lưu vào một biến cục bộ:

Cách làm này giúp giảm thời gian thực hiện chương trình xuống còn 5.9giây, tức là nhanh hơn được 10% Đây là tỷ lệ cải thiện tốc độ bình thường khi

áp dụng kỹ thuật tinh chỉnh mã nguồn Chúng ta còn có thể đưa một biến cốđịnh khác là starting[c] ra khỏi vòng lặp bên trong nhưng thực tế khi thử nghiệmcho thấy không có sự khác biệt rõ rệt nào Điều này cũng là một kết quả thườnggặp của việc tinh chỉnh mã: đôi khi có ích, đôi khi lại không Vì thế, người lậptrình cần phải đo đạc để biết được sự tinh chỉnh nào là có ích và cần thiết Kếtquả thu được có thay đổi theo từng máy cũng như từng trình biên dịch cụ thể

Chúng ta còn có thể thực hiện thêm một thay đổi khác đối với bộ lọc spam.

Vòng lặp trong so sánh toàn bộ chuỗi mẫu với chuỗi cần xét, nhưng theo thuậttoán thì chắc chắn ký tự đầu tiên của 2 chuỗi đã giống nhau Do vậy, ta có thểtinh chỉnh mã nguồn để bắt đầu hàm memcmp từ byte tiếp theo Thử nghiệm

cho thấy sự tinh chỉnh này giúp tăng tốc độ 3%, tuy không nhiều nhưng chỉ phảiđiều chỉnh 3 dòng của chương trình

Trang 21

4.4 Không tối ưu hóa những gì không gây vấn đề

Đôi khi sự tinh chỉnh mã nguồn không đem lại kết quả gì bởi vì được ápdụng đối với những chỗ không phù hợp Cần chắc chắn rằng đoạn mã đangđược tối ưu hóa thật sự là chỗ chiếm nhiều thời gian chạy trong chương trình.Câu chuyện sau đây có thể là ngụy tạo, nhưng cũng nên kể ra làm ví dụ Mộtcông ty nay không còn tồn tại nữa, sử dụng một công cụ theo dõi tốc độ thựchiện của phần cứng ở một chiếc máy đời đầu và thấy rằng máy dùng đến 50phần trăm thời gian thực hiện cùng một dãy vài chỉ thị Các kỹ sư đã tạo một chỉthị để đóng gói lại thành một hàm, chạy lại, và thấy rằng họ không thu được kếtquả gì; họ đã tối ưu hóa vòng lặp nghỉ của hệ điều hành

Một vấn đề khác là chúng ta cần nỗ lực đến mức nào trong việc tăng tốc độchương trình? Tiêu chí chủ yếu là liệu các thay đổi có đem lại lợi ích xác đángnào hay không? Một quy tắc đơn giản là tổng thời gian dùng cho việc cải tiếntăng tốc độ cho chương trình không được vượt quá thời gian mà sự tăng tốc cóthể đem lại được trong suốt thời gian tồn tại của chương trình Theo quy tắcnày, việc cải tiến thuật toán đối với hàm isspam là đáng giá: mất một ngày làm

việc nhưng lại làm lợi được nhiều giờ đồng hồ mỗi ngày Việc loại bỏ chỉ sốmảng ra khỏi vòng lặp bên trong tuy không phải là vấn đề lớn nhưng vẫn có giátrị vì chương trình cung cấp dịch vụ cho một cộng đồng lớn Tối ưu hóa các

dịch vụ công cộng (như bộ lọc spam) hay một thư viện hầu như lúc nào cũng có

giá trị, còn việc tăng tốc độ xử lý cho các chương trình kiểm chứng hầu nhưkhông có giá trị Đối với chương trình hoạt động liên tục nhiều năm, bạn nên tối

ưu hóa tất cả những gì có thể được Thậm chí, sau nhiều tháng sử dụng chươngtrình, bạn có thể tiếp tục việc cải tiến tối ưu hóa chương trình nếu giải pháp mới

có thể giúp tăng 10% tốc độ chương trình

Các chương trình có tính cạnh tranh như trò chơi, trình biên dịch, xử lý vănbản, bảng tính, hệ thống cơ sở dữ liệu đều thuộc nhóm này Tốc độ xử lý ảnhhưởng rất lớn đến sự thành công của các sản phẩm thương mại, ít nhất thôngqua trong các kết quả chấm điểm (benchmark)

Việc đo thời gian chương trình khi thực hiện các thay đổi là rất quan trọng

để chắc chắn rằng chương trình vẫn đang được cải thiện Đôi khi hai cải tiếnkhác nhau có thể có ích một cách riêng rẽ nhưng khi kết hợp với nhau sẽ loại trừlẫn nhau! Cũng có trường hợp cơ chế đo thời gian hoạt động thất thường đếnmức khó rút ra được kết luận chính xác về tác dụng của các thay đổi Ngay cảtrên một hệ thống chỉ có một người dùng, thời gian cũng có thể dao động ngoài

Trang 22

dự tính Nếu sự biến thiên đồng hồ thời gian nội bộ (hay ít nhất là những gìđược báo lại) có thể lên đến 10%, do đó, những thay đổi đem lại sự cải thiện10% rất khó phân biệt với mức độ nhiễu này.

5 TIN CHỈNH MÃ NGUỒN

Có nhiều kỹ thuật làm giảm thời gian thực hiện khi đã xác định được đoạn

mã nguồn chiếm phần lớn thời gian chương trình Dưới đây là một số giải pháp

đề nghị Tuy nhiên, các giải pháp này nên được áp dụng một cách thận trọng vàcần có các thử nghiệm để bảo đảm chương trình vẫn hoạt động đúng Cần nhớrằng, một số trình biên dịch tốt có thể làm giúp bạn một số phần, và thực tế làbạn có thể vô tình ngăn cản điều đó bằng cách làm phức tạp chương trình Bất

cứ những gì bạn thử, hãy đo lường hiệu quả để bảo đảm rằng điều đó có ích

5.1 Tập hợp những biểu thức chung

Nếu một biểu thức tính toán tốn nhiều thời gian xuất hiện nhiều lần, hãythực hiện biểu thức này một lần duy nhất rồi lưu kết quả lại Ví dụ như ởChương 1 – Phong cách lập trình (Style), ta đã gặp một macro dùng để tínhkhoảng cách bằng cách gọi hàm sqrt hai lần trong một dòng lệnh với cùng cácgiá trị, phép tính là như sau:

for (i = 0; i < nstarting[c]; i++)

Ngày đăng: 13/07/2014, 07:20

HÌNH ẢNH LIÊN QUAN

Hình dưới đây phác họa các cấu trúc dữ liệu trên dùng một tập hợp ba chuỗi mẫu bắt đầu bằng ký tự ‘ b ’: - TỐI ƯU HÓA XỬ LÝ CHƯƠNG TRÌNH potx
Hình d ưới đây phác họa các cấu trúc dữ liệu trên dùng một tập hợp ba chuỗi mẫu bắt đầu bằng ký tự ‘ b ’: (Trang 9)
Hình  SEQ Hình \* ARABIC \s 1 1: Minh họa các cấu trúc dữ liệu được - TỐI ƯU HÓA XỬ LÝ CHƯƠNG TRÌNH potx
nh SEQ Hình \* ARABIC \s 1 1: Minh họa các cấu trúc dữ liệu được (Trang 10)
Bảng sau đây thể hiện kết quả ghi nhận quá trình thực hiện chương trình bộ lọc spam. Chương trình dùng một bức thông điệp cố định và một tập hợp cố định gồm 217 cụm từ mẫu, tập hợp này so khớp với bức thông điệp 10000 lần - TỐI ƯU HÓA XỬ LÝ CHƯƠNG TRÌNH potx
Bảng sau đây thể hiện kết quả ghi nhận quá trình thực hiện chương trình bộ lọc spam. Chương trình dùng một bức thông điệp cố định và một tập hợp cố định gồm 217 cụm từ mẫu, tập hợp này so khớp với bức thông điệp 10000 lần (Trang 14)
Bảng 1: Bảng thống kê quá trình thực hiện - TỐI ƯU HÓA XỬ LÝ CHƯƠNG TRÌNH potx
Bảng 1 Bảng thống kê quá trình thực hiện (Trang 15)
Hình 2: Đồ thị thể hiện sự biến thiên tốc độ xử lý của chương trình với kích - TỐI ƯU HÓA XỬ LÝ CHƯƠNG TRÌNH potx
Hình 2 Đồ thị thể hiện sự biến thiên tốc độ xử lý của chương trình với kích (Trang 17)
Bảng 1. Visual Studio 2005 refactorings. - TỐI ƯU HÓA XỬ LÝ CHƯƠNG TRÌNH potx
Bảng 1. Visual Studio 2005 refactorings (Trang 42)
Hình 3. Chọn tập lệnh cho Extract Method refactoring. - TỐI ƯU HÓA XỬ LÝ CHƯƠNG TRÌNH potx
Hình 3. Chọn tập lệnh cho Extract Method refactoring (Trang 43)
Hình 4. Cung cấp tên mới phương thức được trích rút - TỐI ƯU HÓA XỬ LÝ CHƯƠNG TRÌNH potx
Hình 4. Cung cấp tên mới phương thức được trích rút (Trang 44)

TỪ KHÓA LIÊN QUAN

TRÍCH ĐOẠN

TÀI LIỆU CÙNG NGƯỜI DÙNG

TÀI LIỆU LIÊN QUAN

🧩 Sản phẩm bạn có thể quan tâm

w