 Danh hiệu: Advanced Member Nhóm: Member
Gia nhập: 5/25/2010 Bài viết: 16 Điểm: -146 Đến từ: SSE
|
LÀM SAO CHO CHƯƠNG TRÌNH VISUAL FOXPRO CHẠY NHANH HƠN Lập trình viên nào cũng muốn chương trình của mình chạy nhanh, càng nhanh càng tốt. Thế thì làm cách nào để chương trình của Bạn đạt được tốc độ tối ưu? Có một cấu trúc nào đó có thể sử dụng để đạt được mong muốn đó không? Bài viết này không bàn về Rushmore (là một kỹ thuật truy tìm dữ kiện rất độc đáo đã được sử dụng tự động kể từ FoxPro 2.0 trở đi), mà sẽ nói về những thói quen và kỹ thuật lập trình trong Visual Foxpro sao cho các ứng dụng của Bạn đạt được tốc độ cao nhất .
Kiểu dữ liệu Có lẽ đầu tiên phải bàn về kiểu dữ liệu trong Visual Foxpro mà cụ thể là cách dữ liệu được lưu trữ trong tập tin DBF so với cách nó được lưu trữ trong bộ nhớ. Ví dụ: dữ liệu kiểu integer được lưu giữ trong DBF và bộ nhớ giống y như nhau, trong khi dữ liệu kiểu numeric đuợc lưu trữ như một dãy các ký số trong DBF và trong bộ nhớ như một số nhị phân dấu chấm động (floating point binary). Vì thế, kiểu dữ liệu numeric phải được chuyển đổi thành dạng tương ứng khi sử dụng và như thế phải tốn một ít thời gian. Cho nên bất cứ khi nào có thể, nên sử dụng kiểu integer thay cho kiểu numeric hay kiểu double thay cho kiểu float.
Cả hai kiểu date và datetime đều chiếm một số lượng chỗ trữ như nhau trong DBF. Tuy nhiên, dữ liệu date được lưu trữ theo dạng thức chuẩn ANSI có dạng YYYYMMDD, trong khi các vùng kiểu datetime được lưu trữ dưới dạng những con số 8 bytes. Trong bộ nhớ, cả date và datetime đều sử dụng dạng thức số 8 bytes. Như vậy, khi sử dụng kiểu date phải chuyển đổi còn datetime thì không. Do đó mà chúng tôi khuyên bạn nên dùng kiểu datetime cho tất cả các dữ liệu có liên quan đến ngày tháng năm và bỏ thói quen dùng kiểu date. Nếu bạn chỉ cần phần date, thì hãy bỏ qua phần time bằng cách sử dụng trị default 00:00:00 .
Khi nào thì một con số không phải là số? Khi nó không bao giờ được dùng để tính toán. Ví dụ, số điện thoại, số chứng minh nhân dân, số xe, số hoá đơn, mã số thuế, mã số khách hàng, mã số nhân viên . . . là các con số không phải là số. Có khi nào Bạn cần phải tính trung bình cộng các số hoá đơn trong một table nào chưa? Trong các trường hợp như trên chúng tôi khuyên Bạn nên sử dụng kiểu character thay cho kiểu số (numeric, integer, double) và nếu có thể hạn chế các ký tự trong các vùng này chỉ là các ký số mà thôi. Kiểu ký tự character được thao tác nhanh hơn so với kiểu số, và chỉ sử dụng kiểu số khi nó thực sự là một con số (và trong trường hợp này chỉ nên dùng kiểu integer hay double mà thôi).
Vùng memo cho phép Bạn lưu trữ dữ liệu có chiều dài không cố định, nhưng chúng có thể bị lạm dụng do lười biếng. Đừng sử dụng kiểu memo chỉ vì Bạn không muốn tính chiều dài tối đa của dữ liệu sẽ là bao nhiêu. Việc làm này sẽ khiến cho công việc của Bạn nhanh hơn một chút, nhưng nó sẽ làm cho ứng dụng của Bạn chạy chậm đi đáng kể. Những vùng memo cần nhiều thời gian tìm kiếm và xử lý. Vì thế Bạn hãy sử dụng kiểu character bất cứ khi nào có thể thay cho kiểu memo.
Cấu trúc Có một vài cấu trúc thảo chương chạy nhanh hơn những cái khác, như vòng lặp FOR/ENDFOR nhanh hơn vòng lặp DO WHILE/ENDDO, SCAN/ENDSCAN nhanh hơn DO WHILE NOT EOF()/SKIP/ENDDO. Hãy dùng các cấu trúc nhanh hơn này để code chương trình.
Tạo đối tượng • Thể hiện đối tượng là một công việc đòi hỏi nhiều thời gian, không có cách nào “lách” qua được. Thế thì, làm sao Bạn có thể tạo đối tượng nhanh hơn đây? Đừng tạo đối tượng cho tới khi Bạn thật sự cần nó. Khi sử dụng giao diện các đối tượng như PageFrame chẳng hạn, đừng tạo ra sẳn các đối tượng trong một Page cho tới khi chúng được gọi ra sử dụng. Đây gọi là “thể hiện bị trì hoãn” và có thể được làm ngon lành như sau: khi thiết kế form, Bạn vẫn tạo ra các page với tất cả các thành phần của nó như vẫn thường làm, rồi sau đó với từng page Bạn sẽ lưu toàn bộ tập hợp các ô điều khiển (control) của mỗi trang thành một container class bằng cách dùng mục Save as Class trong File menu. Kế đó, Bạn xóa tất cả các ô điều khiển này ra khỏi page. Đặt một Label lên page với thuộc tính visible là .f., trong tình huống Init của label này Bạn viết vào các lệnh sau :
*Label1.Init IF TYPE('This.Parent.Trg1.Name') = 'C' Return Endif SET Classlib to TAM This.Parent.AddObject('Trg1','Trang1') This.Parent.Trg1.Visible = .t. This.Parent.Refresh
Ghi chú: TAM.VCX là thư viện lớp dùng để lưu trữ các ô diều khiển của mỗi trang dưới dạng container class và mang tên lần lượt là Trang1, Trang2, . . .
Trong tình huống Init của form Bạn thêm vào lệnh :
*Form.Init thisform.Trangsach.Page1.Activate
• Nên dùng hàm GetObject() thay cho hàm CreateObject(). GetObject() sẽ đi tìm xem thể hiện của đối tượng cần tạo có hay chưa, trong khi CreateObject() sẽ luôn tạo ra một thể hiện nữa ngay cả khi đối tượng đó đã có rồi.
Làm tươi lại các thể hiện Nếu thật sự muốn nhìn thấy kết quả sửa đổi gì đó của ô điều khiển (control) mà Bạn quan tâm, Bạn hãy sử dụng tình huống làm tươi (Refresh event) lại chính ô điều khiển đó, chứ đừng làm tươi lại toàn bộ form, vì khi thi hành lệnh thiform.refresh thì tất cả các đối tượng trên form đều phải được làm tươi. Tương tự như vậy cho Grid, Page trong PageFrame, và các đối tượng khác mang tính chất thùng chứa (container).
Dùng biểu thức tên (name expression) thay cho macro Bất cứ khi nào có thể, hãy sử dụng biểu thức tên thay cho macro. Macro phải được triển khai và diễn dịch trong chế độ runtime mỗi khi bắt gặp chúng. Vì thế, macro không chỉ làm cho chương trình của Bạn khó đọc, bí hiểm mà còn tốn thời gian thực hiện nhiều hơn nữa. Ngoài việc biểu thức tên thực hiện nhanh hơn macro, nó cũng có thể được dùng bất cứ khi nào VFP muốn sử dụng một cái tên nào đó mà nó muốn. Tên ở đây có thể là tên tập tin, tên cursor, tên vùng, . . . thậm chí là từ khóa cũng được. Bạn hãy xem hai ví dụ sau đây:
Ví dụ 1 : sử dụng macro LOCAL lcFieldName USE HangBan USE TichLuyDS IN 0 LcFieldName = 'TichLuyDS.DoanhsoTL' SCAN SELECT HangBan SCAN FOR HangBan.Mskh = TichLuyDS.Mskh REPLACE &lcFieldName WITH &lcFieldName ; + HangBan.TienHang ENDSCAN ENDSCAN
Ví dụ 2 : sử dụng biểu thức tên LOCAL lcFieldName USE HangBan USE TichLuyDS IN 0 LcFieldName = 'TichLuyDS.DoanhsoTL' SCAN SELECT HangBan SCAN FOR HangBan.Mskh = TichLuyDS.Mskh REPLACE (lcFieldName) WITH EVALUATE(lcFieldName) ; + HangBan.TienHang ENDSCAN ENDSCAN
Ví dụ 2 thực hiện nhanh hơn ví dụ 1. Lưu ý việc dùng hàm EVALUATE() để lấy trị lưu giữ trong biến vùng (field).
Tham chiếu thuộc tính của đối tượng Tham chiếu thuộc tính của đối tượng được thực hiện chậm hơn so với tham chiếu biến bộ nhớ. Khi Bạn cần viết đoạn lệnh mà chúng lại sẽ sử dụng nhiều lần thuộc tính của một đối tượng, nó sẽ chạy nhanh hơn khi Bạn đặt giá trị của thuộc tính này vào một biến bộ nhớ và sau đó dùng biến này trong những lệnh tiếp theo sau.
Ví dụ 1 : Use Tablemau SCAN FOR Vungmau = Thisform.thuoctinhmau . . . . . . . . . ENDSCAN
Ví dụ 2 : sẽ chạy nhanh hơn ví dụ 1 Use Tablemau LOCAL lctrimau Lctrimau = Thisform.thuoctinhmau SCAN FOR Vungmau = lctrimau . . . . . . . . . ENDSCAN
Một cách khác cũng nhằm làm tăng tốc độ truy cập thuộc tính của đối tượng là sử dụng cấu trúc WITH/ENDWITH. Khi cần truy xuất một số các thuộc thuộc tính của cùng một đối tượng, bạn có thể làm cho chúng nhanh hơn bằng cách sử dụng WITH/ENDWITH.
Ví dụ 1 : THISFORM.thuoctinh1= 'ABC' THISFORM.thuoctinh2= 'ABC' THISFORM.thuoctinh3= 'ABC' THISFORM.thuoctinh4= 'ABC' THISFORM.thuoctinh5= 'ABC' THISFORM.thuoctinh6= 'ABC' THISFORM.thuoctinh7= 'ABC' THISFORM.thuoctinh8= 'ABC'
Ví dụ 2 : sẽ chạy nhanh hơn ví dụ 1 WITH THISFORM .thuoctinh1= 'ABC' .thuoctinh2= 'ABC' .thuoctinh3= 'ABC' .thuoctinh4= 'ABC' .thuoctinh5= 'ABC' .thuoctinh6= 'ABC' .thuoctinh7= 'ABC' .thuoctinh8= 'ABC' ENDWITH
Những lời “nhắn nhủ” khác • Bạn có thể sử dụng thuộc tính LockScreen cuả form để ngăn không cho cập nhật nội dung của form trong lúc đang thao tác. Gán cho thuộc tính LockScreen trị .T. trước khi bắt đầu thao tác, và sau đó khi thao tác hoàn tất gán lại trị .F. cho thuộc tính này. Mặc dù điều này không cải thiện được thời gian xử lý bao nhiêu, nhưng nó làm cho giao diện không bị rối vì người sử dụng không nhìn thấy những lần làm tươi xảy ra trong quá trình thao tác. • Luôn có lệnh SET DOHISTORY OFF tại điểm bắt đầu chương trình. Và bất kỳ lúc nào có thể hãy sử dụng lệnh SET TALK OFF. Cả DOHISTORY và TALK đều tiêu tốn nhiều thời gian để làm công việc của chúng, khóa chúng lại bằng cách OFF sẽ cải thiện được đáng kể thời gian xử lý. • Sử dụng DataEnviroment của form hay của report sẽ nhanh hơn là dùng lệnh USE để mở table hay view. • Xóa các đối tượng ra khỏi bộ nhớ ngay khi chúng không còn cần thiết nữa. Việc làm này sẽ giải phóng bộ nhớ dành chỗ cho các đối tượng khác sử dụng. • Hãy thay các cấu trúc IF lồng bằng DO CASE với các CASE có độ ưu tiên thực hiện từ cao xuống thấp thường sẽ cải thiện được thời gian xử lý khá nhiều.
Tối ưu hóa một ứng dụng là một việc làm đòi hỏi phải cẩn thận và chịu khó. Nếu Bạn mới ở giai đoạn bắt đầu lập trình thì dễ rồi, nhưng nếu Bạn đã là một lập trình viên kỳ cựu thì việc thay đổi thói quen và phong cách lập trình cũ không phải là việc dễ dàng. Hy vọng những ý kiến trình bày ở trên sẽ giúp cho Bạn cải thiện được phần nào thời gian chạy ứng dụng của mình ./.

|