Tăng hiệu suất chương trình C#

Đây là 1 số ít kinh nghiệm tay nghề về tối ưu hóa mã nguồn C # sau một khoảng chừng thời hạn thao tác với nó. Bạn hoàn toàn có thể vận dụng 1 số ít thủ pháp này trong những ngôn từ khác như VB.Net, Java …
Để đo thời hạn thực thi của những đoạn mã ví dụ bên dưới, bạn hoàn toàn có thể dùng DateTime. Now. Ticks lưu thời gian mở màn và kết thúc. Tuy nhiên. Net cung ứng cho bạn sẵn đối tượng người dùng Stopwatch ( đồng hồ đeo tay bấm giờ ) nằm trong khoảng trống tên System. Diagnostics để dùng cho những việc làm dạng này .
Trong mỗi phần tôi sẽ so sánh hai chiêu thức ( đoạn mã ), chiêu thức thứ hai sẽ là chiêu thức tối ưu hơn cho bạn lựa chọn. Mặc dù những giải pháp sửa chữa thay thế hoàn toàn có thể tốt hơn nhưng không hẳn đã là tối ưu, việc tối ưu một đoạn mã yên cầu sự hiểu biết và nghiên cứu và phân tích khá sâu vào nền tảng. Net, không chỉ có vậy còn phụ vào thuật toán bạn sử dụng trong từng trường hợp .

1. So sánh chuỗi:

Ở đây tôi dùng hai giải pháp so sánh chuỗi thường sử dụng ( có phân biệt hoa thường ). Điểm độc lạ giữa hai phương pháp này là phương pháp thứ 1 là tĩnh ( static ) nên ta hoàn toàn có thể gọi trực tiếp từ lớp String .
– ( 1 ) int String. Compare ( string strA, string strB, bool ignoreCase )
– ( 2 ) bool string. Equals ( string value, StringComparison comparisonType )

string s1=”aaa”;
string s2=”AAA”;

Đoạn mã 1:

Đoạn mã 2:

Visual C # Code :
Select All | Show/Hide

  1. for (int i = 0; i < 100000; i+ +)
  2.     {

  3. bool b = s1.Equals(s2,StringComparison.OrdinalIgnoreCase);s1s2, StringComparison
  4.     }

Đoạn mã thứ nhất chạy chậm hơn đoạn thứ hai hơn 3 lần. Tuy nhiên nếu bạn sử dụng tham số StringComparison.CurrentCultureIgnoreCase cho phương thức Equals thì tốc độ giữa hai đoạn mã là xấp xỉ. Một số người dùng cách chuyển cả hai chuỗi về dạng chữ hoa hoặc chữ thường rồi so sánh sẽ tốn thời gian lâu nhất (hơn 2 lần so với cách một).
2. Xây dựng chuỗi – String và StringBuilder:

Đây có lẽ là điều bạn thường gặp và cũng đã nắm bắt được sự khác biệt rõ ràng giữa chúng. Với số lần lặp tương đối lớn bạn sẽ có một khoảng thời gian chờ tương đối lâu khi làm việc với lớp String, vì thế tôi sẽ giảm số lần lặp xuống trong ví dụ này.
Đoạn mã 1:

Đoạn mã 2:

Visual C # Code :
Select All | Show/Hide

  1. =  StringBuilder();

    StringBuilder str new StringBuilder

  2. for (int i = 0; i < 10000; i+ +)
  3.     {

  4.         str.Append(“a”);

  5.     }

Kết quả cho ta thấy đoạn mã một chạy chậm hơn khoảng chừng từ 200 đến 300 lần đoạn mã hai. Nguyên nhân là toán tử + của lớp string sẽ tạo ra một đối tượng người dùng string mới trong mỗi lần lặp, trong khi phương pháp Append của StringBuilder sẽ nối trực tiếp vào chuỗi hiện tại .
Tuy nhiên cũng cần quan tâm điều này hoàn toàn có thể ngược lại nếu như bạn cần chuyển chuỗi StringBuilder thành String trong mỗi lần lặp. Tốc độ thực thi của đoạn mã thứ hai sẽ lâu hơn so với đoạn mã một. Hãy kiểm chứng bằng cách chạy thử đoạn mã hai sau khi sửa lại như sau :

Đoạn mã 2 (đã sửa):

Visual C # Code :
Select All | Show/Hide

  1. = ();

    StringBuilder str new StringBuilder

  2. ;string strRet
  3. for (int i = 0; i < 10000; i+ +)
  4.     {

  5.         str.Append(“a”);

  6.         strRet = str.ToString();

  7.     }

3. Nối chuỗi – Phương thức Insert() và toán tử +:
Bạn thường sử dụng hai cách để nối hai chuỗi lại với nhau là dùng toán tử + và phương thức Insert() của đối tượng string. Cách đầu tiên được sử dụng nhiều hơn vì cách viết tiện lợi và dễ hiểu hơn, tuy nhiên bạn chỉ có thể nối vào đầu hoặc cuối chuỗi. Hãy thử so sánh xem phương pháp nào cho tốc độ thực thi nhanh hơn, giả sử bạn cần nối một chuỗi con vào đầu một chuỗi.

Đoạn mã 1:

Đoạn mã 2:

Nếu chạy thử vài lần, bạn sẽ nhận thấy rằng đoạn mã thứ hai chạy nhanh gấp đôi đoạn mã một. Tuy nhiên nếu như không khởi tạo lại giá trị của biến str trong mỗi lần lặp, tốc độ của hai đoạn mã này là xấp xỉ nhau.
4. Cắt chuỗi – Substring() và Remove():

Hai phương pháp trên của lớp string có công dụng khá giống nhau là cắt bỏ một phần chuỗi nguồn. Cả hai phương pháp đều có 2 kiểu nạp chồng, và đều nhu yếu truyền vào vị trí khởi đầu của chuỗi. Tùy vào trường hợp, Substring ( ) thích hợp cho việc cắt bỏ chuỗi phía trước, còn Remove ( ) lại thường dùng để cắt bỏ phía sau chuỗi. Trong ví dụ này tôi sẽ dùng hai phương pháp này để cắt bỏ 1 kí tự phía trước chuỗi :

Đoạn mã 1:

Visual C # Code :
Select All | Show/Hide

  1. ;string str
  2. for (int i = 0; i < 10000; i+ +)
  3.     {

  4. = “string”;str
  5.         str = str.Remove(0, 1);

  6.     }

Đoạn mã 2:

Visual C # Code :
Select All | Show/Hide

  1. ;string str
  2. for (int i = 0; i < 10000; i+ +)
  3.     {

  4. = “string”;str
  5.         str = str.Substring(1);

  6.     }

Sự khác biệt giữa đoạn mã hai so với đoạn mã một là tốc độ nhanh hơn khoảng 2 lần. Tuy nhiên sự khác biệt này sẽ trở nên khó phân biệt nếu như bạn dùng chúng để cắt ở vị trí khác, như là cuối chuỗi chẳng hạn.
5. Chuyển đối tượng về dạng chuỗi – Format() và ToString();
Format là một phương thức khá hiệu quả trong một số trường hợp bạn cần thêm các tham số và một chuỗi, sử dụng tương tự như cách bạn in một chuỗi ra màn hình console bằng phương thức WriteLine().

Đoạn mã 1:

Visual C # Code :
Select All | Show/Hide

  1. = “”;string str“”
  2. = 1;int obj
  3. for (int i = 0; i < 100000; i+ +)
  4.     {

  5. = String.Format(“{0}{0}{0}{0}{0}{0}{0}{0}{0}{0}”, obj);str ”, obj
  6.     }

Đoạn mã 2:

Visual C # Code :
Select All | Show/Hide

  1. = “”;string str“”
  2. = 1;int obj
  3. for (int i = 0; i < 100000; i+ +)
  4.     {

  5. string s = obj.ToString();obj
  6.         str = s + s + s + s + s + s + s + s + s + s;

  7.     }

Ở đây tôi tạo ra một đối tượng string với giá trị là mười số 1 trong mỗi lần lặp. Cả hai phương pháp này đều chạy khá lâu với số lần lặp là 100000. Tuy nhiên đoạn mã thứ nhất sẽ tốn thời gian gấp gần 5 lần so với đoạn mã thứ hai, mặc dù đoạn mã thứ hai còn sử dụng toán tử cộng chuỗi.
6. Sự khác biệt giữa các phương thức nạp chồng (overloaded):
Bạn có thể không để ý rằng giữa các phương thức nạp chồng, thực hiện cùng một công việc lại có sự khác biệt về khoảng thời gian mà chúng thực thi. Điều này thường thấy trong các phương thức với tham số là một hoặc nhiều kiểu đối tượng được tạo ra từ những thành phần đơn giản hơn.
Chẳng hạn như phương thức khởi tạo của đối tượng Rectangle, ta sẽ thử xét hai phương thức:

– (1) Rectangle (Point location, Size size)
– (2) Rectangle (int x, int y, int width, int height)

Sự khác biệt về thời gian thực thi giữa 2 phương thức phụ thuộc vào đoạn mã chúng ta viết.
Nếu bạn so sánh giữa 2 đoạn mã sau:

Đoạn mã 1:

Đoạn mã 2:

Visual C# Code:

Select All | Show/Hide

  1. for (int i = 0; i < 100000; i+ +)
  2.     {

  3. = (i,i,i,i);

    Rectangle rec new Rectanglei,i,i,i

  4.     }

Bạn hoàn toàn có thể nhận thấy là đoạn mã thứ nhất chạy lâu hơn đoạn thứ hai khoảng chừng 7 lần. Lý do xảy ra điều này bạn hoàn toàn có thể đoán được là phương pháp thứ nhất phải tạo ra 2 đối tượng người dùng trong mỗi lần lặp .

7. Hạn chế sử dụng khối try catch:

Việc giải quyết và xử lý những ngoại lệ trong C # thường chiếm một khoảng chừng thời hạn tương đối lâu. Một số ngoại lệ hoàn toàn có thể Dự kiến trước được, và thay vì sử dụng khổi try catch để bao đoạn mã không bảo đảm an toàn này lại, bạn hãy tự giải quyết và xử lý trải qua những dòng lệnh kiểm tra trước khi để đoạn mã liên tục thực thi. Đây là một ví dụ :
int a = 0, b = 10 ;

Đoạn mã 1:

Visual C # Code :
Select All | Show/Hide

  1. for (int i = 0; i < 1000; i+ +)
  2.     {

  3. try
  4.         {

  5. int c = b / a;
  6.         }

  7. catch { }
  8.     }

Đoạn mã 2:

Visual C # Code :
Select All | Show/Hide

  1. for (int i = 0; i < 1000; i+ +)
  2.     {

  3. if (a = = 0)
  4. continue;
  5. int c = b / a;
  6.     }

Dòng lệnh int c = b / a đương nhiên luôn ném ra ngoại lệ Divide by Zero ( chia cho 0 ) nếu được thực thi. Tuy nhiên ngoại lệ này bạn hoàn toàn có thể đoán trước và kiểm tra mẫu số phải khác 0 trước khi liên tục hay không. Sự thận trọng như trong đoạn mã 2 giúp bạn tiết kiệm ngân sách và chi phí được thời hạn khoảng chừng 30,000 ( 30 nghìn ) lần so với đoạn mã 1 .

8. Hạn chế việc gọi phương thức:

Việc gọi phương pháp nhiều lần hoàn toàn có thể làm giảm vận tốc thực thi của chương trình so với việc viết trực tiếp thân hàm vào nơi thiết yếu. Vì thế so với những phương pháp có nội dung đơn thuần và không được gọi ở nhiều nơi khác nhau, bạn nên vô hiệu bớt đi những phương pháp này. Điều này thường ít xảy ra nhưng hoàn toàn có thể giúp bạn cẩn trọng hơn trong việc quyết định hành động có nên tạo ra một phương pháp mới hay không .
Giả sử bạn có 1 phương pháp Method ( ) đơn thuần như sau :
Bạn có hai cách để thực thi hai phương pháp trên như sau :

Đoạn mã 1:

Visual C # Code :
Select All | Show/Hide

  1. for (int i = 0; i < 1000000; i+ +)
  2.     {

  3.         Method();

  4.     }

Đoạn mã 2:

Visual C # Code :
Select All | Show/Hide

  1. for (int i = 0; i < 1000000; i+ +)
  2.     {

  3. int a = 1, b = 2;, b
  4. int c = a + b;
  5.     }

Đoạn mã thứ hai chạy nhanh đoạn thứ nhất 3 lần. Các lệnh nhảy mặc dầu rất tốn rất ít ngân sách nhưng với số lượng nhiều hoàn toàn có thể làm chậm vận tốc thực thi của chương trình khá rõ ràng .

9. Sử dụng cấu trúc thay cho lớp:

Đối với những kiểu tài liệu đơn thuần và không cần tham chiếu, bạn nên sử dụng cấu trúc ( structure ) thay cho lớp ( class ), điều này sẽ giúp giảm bớt ngân sách tài nguyên tiêu tốn cho chương trình của bạn. Tuy nhiên bạn cũng cần xem xét dựa vào nhu yếu của dự án Bất Động Sản trước khi quyết định hành động dùng struct hay class cho tương thích .
Giả sử bạn có một lớp và một cấu trúc có cùng thành viên và thuộc tính đơn thuần như sau :
Hai đoạn mã cũng triển khai cùng một trách nhiệm :

Đoạn mã 1:

Visual C # Code :
Select All | Show/Hide

  1. for (int i = 0; i < 1000000; i+ +)
  2.     {

  3. = ();

    MyClass myClass new MyClass

  4. .Value = 1;myClass
  5.     }

Đoạn mã 2:

Visual C # Code :
Select All | Show/Hide

  1. for (int i = 0; i < 1000000; i+ +)
  2.     {

  3. = ();

    MyStruct myStruct new MyStruct

  4. .Value = 1;myStruct
  5.     }

Khi chạy thử bạn hoàn toàn có thể nhận thấy đoạn mã thứ hai chạy nhanh hơn khoảng chừng trên 4 lần so với đoạn mã thứ nhất. Lý do chính khá đơn thuần là cấu trúc đơn thuần và có ít tính năng hơn lớp, cho nên vì thế như đã nói trước, bạn chỉ nên sử dụng so với những kiểu tài liệu đơn thuần, thành viên của nó thường là những kiểu tài liệu đã được kiến thiết xây dựng sẵn .

10. Sử dụng tập hợp (collection) có định kiểu:

Mục đích của việc này là giúp hạn chế tối đa việc ép kiểu khi bạn thao tác với những tập hợp này. Thường thì tất cả chúng ta chỉ chứa một loại đối tượng người dùng trong một tập hợp, cho nên vì thế thay vì dùng lớp ArrayList để tàng trữ, bạn hãy thử dùng List. Các tập hợp có định kiểu được cung ứng trong namespace System. Collections. Generic .

11. Mảng (array) và tập hợp (collection) – tốc độ hay sự linh hoạt:

Bạn hoàn toàn có thể đã biết rằng việc sử dụng mảng sẽ giúp truy xuất nhanh hơn tuy hơn lại không linh động bằng tập hợp. Về mặt kim chỉ nan, tập hợp giống như một list link ( linked list ) với năng lực cấp phát động để cung ứng những thao tác thêm, xóa theo vị trí mà mảng không tương hỗ. Trong một số ít trường hợp, nếu không cần đến những công dụng này của tập hợp, bạn nên sử dụng mảng để tối ưu cho chương trình của mình .

Đoạn mã 1:

Visual C # Code :
Select All | Show/Hide

  1.  list = ();

    Listlist new List

  2. for (int i = 0; i < 1000000; i+ +)
  3.     {

  4.         list.Add(1);

  5.     }

Đoạn mã 2:

Visual C # Code :
Select All | Show/Hide

  1. int[] arr = new int[1000000];arr
  2. for (int i = 0; i < arr.Length; i+ +)arr
  3.     {

  4.         arr[i] = 1;

  5.     

    }

Tốc độ thực thi của đoạn mã thứ hai hoàn toàn có thể nhanh hơn 4-6 lần đoạn mã một. Tuy nhiên nếu bạn sử dụng ArrayList trong đoạn mã một, sự độc lạ này có tăng lên đến 15 lần. Một lần nữa bạn thấy sự cải tổ đáng kể khi sử dụng tập hợp có định kiểu .
Trên đây chỉ là một vài kinh nghiệm tay nghề cơ bản, bạn hoàn toàn có thể tự khám phá và mày mò thêm trong quy trình thực hành thực tế .
( Các bạn chú ý quan tâm những dấu nháy kép khi dán vào trong hành lang cửa số soạn thảo C # thì cần sửa lại cho đúng )

Rate this post
Xem thêm  Cách cày thẻ kinh nghiệm LV 15 Miễn Phí siêu nhanh | thông tin về game mới cập nhật tại Bem2

Bài viết liên quan

Để lại ý kiến của bạn:

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *