Về lý thuyết, một phương thức static sẽ hoạt động tốt hơn một chút so với phương thức instance, tất cả những thứ khác đều bằng nhau, vì có thêm this
tham số ẩn .
Trong thực tế, điều này tạo ra sự khác biệt nhỏ đến mức nó sẽ bị ẩn trong nhiễu của các quyết định trình biên dịch khác nhau. (Do đó hai người có thể "chứng minh" một người tốt hơn người kia với kết quả không đồng ý). Ít nhất là vì this
nó thường được thông qua trong một sổ đăng ký và thường có trong sổ đăng ký đó để bắt đầu.
Điểm cuối cùng này có nghĩa là về lý thuyết, chúng ta nên mong đợi một phương thức tĩnh lấy một đối tượng làm tham số và thực hiện một điều gì đó với nó sẽ kém hơn một chút so với phương thức tương đương như một thể hiện trên cùng một đối tượng đó. Tuy nhiên, một lần nữa, sự khác biệt rất nhỏ đến mức nếu bạn cố gắng đo lường nó, bạn có thể sẽ phải đo lường một số quyết định trình biên dịch khác. (Đặc biệt là vì khả năng nếu tham chiếu đó được đăng ký trong toàn bộ thời gian cũng khá cao).
Sự khác biệt về hiệu suất thực sự sẽ phụ thuộc vào việc bạn có các đối tượng trong bộ nhớ một cách giả tạo để làm điều gì đó tự nhiên là tĩnh, hay bạn đang kết nối các chuỗi truyền đối tượng theo những cách phức tạp để làm những gì tự nhiên nên có.
Do đó đối với số 1. Khi việc giữ trạng thái không phải là mối quan tâm, tốt hơn hết bạn nên ở trạng thái tĩnh, bởi vì đó là điều mà tĩnh là để làm . Đó không phải là mối quan tâm về hiệu suất, mặc dù có một quy tắc tổng thể để chơi tốt với tối ưu hóa trình biên dịch - nhiều khả năng ai đó đã nỗ lực tối ưu hóa các trường hợp sử dụng bình thường hơn là những trường hợp sử dụng lạ.
Số 2. Không có gì khác biệt. Có một mức chi phí nhất định cho mỗi lớp đối với mỗi thành viên mà nó liên quan đến cả lượng siêu dữ liệu có, số lượng mã có trong tệp DLL hoặc EXE thực tế và sẽ có bao nhiêu mã được ghép nối. Điều này giống nhau cho dù là phiên bản hay tĩnh.
Với mục 3, this
làthis
vậy. Tuy nhiên lưu ý:
Các this
tham số được truyền vào một thanh ghi đặc biệt. Khi gọi một phương thức thể hiện trong cùng một lớp, nó có thể sẽ nằm trong thanh ghi đó rồi (trừ khi nó được lưu trữ và thanh ghi được sử dụng vì lý do nào đó) và do đó không cần thực hiện hành động nào để thiết lậpthis
nó thành những gì nó cần được đặt thành . Điều này áp dụng cho một mức độ nhất định, ví dụ: hai tham số đầu tiên của phương thức là hai tham số đầu tiên của một lệnh gọi mà nó thực hiện.
Vì sẽ rõ ràng rằng this
không phải là null, điều này có thể được sử dụng để tối ưu hóa cuộc gọi trong một số trường hợp.
Vì rõ ràng đó this
không phải là null, điều này có thể làm cho các cuộc gọi phương thức nội tuyến trở lại hiệu quả hơn, vì mã được tạo ra để giả mạo cuộc gọi phương thức có thể bỏ qua một số kiểm tra null mà nó có thể cần.
Điều đó nói rằng, séc null rất rẻ!
Cần lưu ý rằng các phương thức tĩnh chung chung hoạt động trên một đối tượng, thay vì các phương thức cá thể, có thể giảm một số chi phí được thảo luận tại http://joeduffyblog.com/2011/10/23/on-generics-and-some-of- tổng chi phí liên quan / trong trường hợp tĩnh nhất định đó không được gọi cho một loại nhất định. Như anh ấy nói "Như một điều gì đó sang một bên, hóa ra các phương pháp mở rộng là một cách tuyệt vời để làm cho các nội dung trừu tượng chung chung trở nên đáng chơi hơn."
Tuy nhiên, lưu ý rằng điều này chỉ liên quan đến việc khởi tạo các kiểu khác được sử dụng bởi phương thức, không tồn tại. Như vậy, nó thực sự không áp dụng cho nhiều trường hợp (một số phương thức thể hiện khác đã sử dụng kiểu đó, một số mã khác ở nơi khác đã sử dụng kiểu đó).
Tóm lược:
- Chủ yếu là chi phí hiệu suất của instance và static dưới đây không đáng kể.
- Ví dụ, chi phí phát sinh sẽ đến khi bạn lạm dụng static hoặc ngược lại. Nếu bạn không đưa nó vào quyết định của mình giữa tĩnh và phiên bản, bạn có nhiều khả năng nhận được kết quả chính xác.
- Có một số trường hợp hiếm hoi trong đó các phương thức chung tĩnh trong một kiểu khác dẫn đến việc tạo ra ít kiểu hơn so với các phương thức chung ví dụ, có thể khiến nó đôi khi có một lợi ích nhỏ là hiếm khi được sử dụng (và "hiếm khi" đề cập đến kiểu mà nó được sử dụng với thời gian tồn tại của ứng dụng, không phải tần suất nó được gọi). Một khi bạn hiểu những gì anh ấy đang nói trong bài viết đó, bạn sẽ thấy rằng dù sao thì nó 100% không liên quan đến hầu hết các quyết định tĩnh so với phiên bản. Chỉnh sửa: Và nó chủ yếu chỉ có chi phí đó với ngen, không phải với mã jitted.
Chỉnh sửa: Một lưu ý về cách kiểm tra null rẻ như thế nào (mà tôi đã tuyên bố ở trên). Hầu hết các kiểm tra null trong .NET hoàn toàn không kiểm tra null, thay vào đó chúng tiếp tục những gì chúng sẽ làm với giả định rằng nó sẽ hoạt động và nếu một ngoại lệ truy cập xảy ra, nó sẽ được chuyển thành a NullReferenceException
. Như vậy, về mặt khái niệm, mã C # liên quan đến kiểm tra null vì nó đang truy cập vào một thành viên cá thể, chi phí nếu nó thành công thực sự là 0. Một ngoại lệ sẽ là một số lệnh gọi nội tuyến, (vì chúng muốn hoạt động như thể chúng được gọi là thành viên thể hiện) và chúng chỉ nhấn vào một trường để kích hoạt cùng một hành vi, vì vậy chúng cũng rất rẻ và dù sao thì chúng vẫn có thể bị loại (ví dụ: nếu bước đầu tiên trong phương thức liên quan đến việc truy cập một trường như nó vốn có).