2009-03-11 32 views
38

Tôi đã poking xung quanh trong XNA và thấy rằng lớp Vector3 trong nó đã được sử dụng lĩnh vực công cộng thay vì tài sản. Tôi đã thử một điểm chuẩn nhanh chóng và thấy rằng, cho một sự khác biệt là khá ấn tượng (thêm hai Vectors với nhau một 100 triệu lần mất 2.0s với tài sản và 1,4 với các lĩnh vực). Đối với một loại tham chiếu, sự khác biệt dường như không lớn nhưng nó ở đó.Tại sao các trường công khai nhanh hơn các thuộc tính?

Vậy tại sao vậy? Tôi biết rằng thuộc tính được biên dịch thành các phương thức get_Xset_X, sẽ phải trả phí gọi phương thức. Tuy nhiên, không phải những getters/setters đơn giản này luôn luôn được JIT xếp hàng? Tôi biết bạn không thể đảm bảo những gì JIT quyết định làm, nhưng chắc chắn điều này là khá cao trong danh sách xác suất? Còn gì khác có thể tách một lĩnh vực công khai khỏi một tài sản ở cấp độ máy?

Và một điều tôi đã tự hỏi: làm thế nào là một thuộc tính tự động thực hiện (public int Foo { get; set; }) 'tốt hơn' OO-thiết kế hơn một lĩnh vực công cộng? Hoặc tốt hơn đã nói: hai số này là khác nhau như thế nào? Tôi biết rằng làm cho nó một tài sản dễ dàng hơn với sự phản ánh, nhưng bất cứ điều gì khác? Tôi đặt cược câu trả lời cho cả hai câu hỏi là điều tương tự.

BTW: Tôi đang sử dụng .NET 3.5 SP1 mà tôi tin rằng các vấn đề cố định trong đó phương pháp có cấu trúc (hoặc phương pháp của cấu trúc, tôi không chắc) không được xếp hàng. Tôi nghĩ rằng tôi đang sử dụng nó ít nhất, nó chắc chắn được cài đặt nhưng sau đó một lần nữa, tôi đang sử dụng Vista 64-bit với SP1 mà nên có DX10.1 ngoại trừ tôi không có DX10.1 ..

Ngoài ra: yeah, tôi đã chạy một xây dựng phát hành :)

EDIT: tôi đánh giá cao câu trả lời chàng trai nhanh chóng, nhưng tôi chỉ ra rằng tôi làm biết rằng một truy cập tài sản là một phương pháp gọi, nhưng mà tôi don' t biết lý do tại sao, có lẽ, trong lót phương pháp là chậm hơn so với một truy cập trực tiếp lĩnh vực.

EDIT 2: Vì vậy, tôi đã tạo ra một struct rằng sử dụng rõ ràng GetX() phương pháp (o làm thế nào tôi không bỏ lỡ ngày Java của tôi ở tất cả) và thực hiện như nhau cho dù tôi vô hiệu hóa trong-lót trên đó (thông qua [MethodImplAttribute(MethodImplOptions.NoInlining)]) hay không, vì vậy kết luận: phương pháp không tĩnh dường như không bao giờ được gạch chân, ngay cả trên cấu trúc.

Tôi nghĩ rằng có những ngoại lệ, trong đó JIT có thể chọn phương thức ảo gọi đi. Tại sao điều này không thể xảy ra trên các cấu trúc mà không biết thừa kế và do đó một cuộc gọi phương thức chỉ có thể trỏ đến một phương thức có thể, đúng không? Hoặc là bởi vì bạn có thể thực hiện một giao diện trên nó?

Đây là loại một sự xấu hổ, vì nó sẽ thực sự làm cho tôi suy nghĩ về việc sử dụng tài sản trên hiệu suất thứ quan trọng, tuy nhiên sử dụng các lĩnh vực khiến tôi cảm thấy bẩn và tôi cũng có thể viết những gì tôi đang làm trong C.

EDIT 3: Tôi đã tìm thấy this đăng bài về cùng một chủ đề chính xác. Kết luận cuối cùng của ông là cuộc gọi tài sản đã được tối ưu hóa. Tôi cũng có thể thề rằng tôi đã đọc nhiều lần rằng các thuộc tính getter/setter đơn giản sẽ được xếp hàng, mặc dù là callvirt trong IL. Vậy tôi có bị điên không?

EDIT 4: Reed Copsey gửi câu trả lời trong một chú thích bên dưới:

Re: Edit3 - xem bình luận cập nhật của tôi: Tôi tin rằng đây là x86 JIT vs vấn đề x64 JIT. JIT trong x64 không phải là trưởng thành. Tôi hy vọng MS sẽ cải thiện điều này một cách nhanh chóng khi có thêm hệ thống 64 bit trực tuyến mỗi ngày. - Reed Copsey

Và câu trả lời của tôi cho câu trả lời của mình:

Cảm ơn, đây là câu trả lời! Tôi đã cố gắng xây dựng một x86 và tất cả các phương thức đều nhanh và nhanh hơn nhiều so với x64. Điều này thực sự rất gây sốc cho tôi, tôi không biết mình đang sống trong thời kỳ đồ đá trên hệ điều hành 64-bit của mình .. Tôi sẽ đưa nhận xét của bạn vào câu trả lời để nó nổi bật hơn. - JulianR

Cảm ơn mọi người!

+0

Câu hỏi: Điều gì sẽ xảy ra nếu trường công khai nhưng cũng có thuộc tính. Vậy nó có được gạch chân không? – Quibblesome

+0

Có vẻ như không, không. – JulianR

+1

Re: Edit3 - xem bình luận cập nhật của tôi: Tôi tin rằng đây là vấn đề JIT x86 JIT vs x64 JIT. JIT trong x64 không phải là trưởng thành. Tôi hy vọng MS sẽ cải thiện điều này một cách nhanh chóng khi có thêm hệ thống 64 bit trực tuyến mỗi ngày. –

Trả lời

15

Chỉnh sửa 2:

tôi đã có một suy nghĩ tiềm năng ở đây:

Bạn nói rằng bạn đang chạy trên x64. Tôi đã thử nghiệm cùng một vấn đề này trên x86, và thấy hiệu suất tương tự khi sử dụng các thuộc tính tự động so với các trường. Tuy nhiên, nếu bạn nhìn xung quanh trên danh sách kết nối và gửi thư/diễn đàn, có rất nhiều tài liệu tham khảo trực tuyến về thực tế là JIT của x64 CLR là một cơ sở mã khác nhau và có các đặc tính hiệu suất rất khác với JIT x86. Tôi đoán đây là một nơi mà x64 vẫn tụt lại phía sau.

Ngoài ra, FYI, cấu trúc/phương pháp/v.v. được cố định trong .net 3.5sp1 ở phía x86 và thực tế là các cuộc gọi phương thức lấy cấu trúc làm tham số sẽ không bao giờ được in x86 trước .net3 .5sp1. Đó là khá nhiều không liên quan đến cuộc thảo luận này trên hệ thống của bạn.


Sửa 3:

Một điều: Là tại sao XNA đang sử dụng các lĩnh vực. Tôi thực sự đã ở Game Fest, nơi họ tuyên bố XNA. Rico Mariani đã nói chuyện với nhau về việc anh ấy đã đưa ra nhiều điểm giống nhau trên blog của mình. Có vẻ như những người XNA có những ý tưởng tương tự khi họ phát triển một số đối tượng cốt lõi. Xem:

http://blogs.msdn.com/ricom/archive/2006/09/07/745085.aspx

Đặc biệt, hãy kiểm tra điểm # 2.


Còn về lý do thuộc tính tự động là tốt hơn so với các lĩnh vực công cộng:

Chúng cho phép bạn thay đổi thực hiện trong v2 của lớp học của bạn, và thêm logic vào tài sản thói quen get/set khi cần thiết, mà không thay đổi giao diện của bạn cho người dùng cuối. Điều này có thể có ảnh hưởng sâu sắc đến khả năng duy trì thư viện và mã của bạn theo thời gian.

---- Từ bài gốc - nhưng phát hiện ra đây không phải là vấn đề --------

Có phải bạn đang chạy một phiên bản xây dựng ngoài của VS? Đó có thể là một giải thích cho lý do tại sao mọi thứ không được tối ưu hóa. Thông thường, nếu bạn đang chạy trong VS, thậm chí một bản phát hành được tối ưu hóa, quy trình lưu trữ VS vô hiệu hóa nhiều chức năng của JIT. Điều này có thể gây ra điểm chuẩn hiệu suất để thay đổi.

+0

Có, tôi đã thử đóng tất cả các trường hợp của VS và chạy .exe trong thư mục Release, nhưng cùng một kết quả (mặc dù cả hai phiên bản hơi nhanh hơn bên ngoài VS). Và vâng, đó là lý do chính đáng để sử dụng các thuộc tính ngay cả khi bạn không điền vào tập hợp/lần đầu tiên :) – JulianR

+0

Các trường hợp sử dụng tốt nhất cho các loại cấu trúc là những cách phân phối một vài biến cùng với băng keo (ví dụ: tọa độ của một điểm).Nếu một cấu trúc được cho là chấp nhận bất kỳ cặp số nguyên nào và báo cáo chúng là X và Y, thì không có bất kỳ hành vi hữu ích nào trong phiên bản tương lai của loại có thể thêm vào các trình truy cập thuộc tính X và Y mà không phá vỡ mọi thứ. Tốt hơn để có một cấu trúc nói nó là gì (một trường X và một trường Y), hơn là giữ nó "bí mật". – supercat

3
  • lĩnh vực công cộng là nhiệm vụ trực tiếp
  • Thuộc tính là phương pháp, mã thì hơn, không đáng kể nhưng nhiều hơn.
+0

Vâng tôi biết như tôi đã nói, nhưng khi một phương thức getter/setter được inlined, không phải là truy cập trực tiếp vào trường sao lưu của thuộc tính không? – JulianR

+0

Julian - vâng, nó nên. Bạn có đang chạy trong VS không? Nếu vậy, dự án máy chủ của VS vô hiệu hóa nhiều tối ưu hóa của JIT, ngay cả khi đó là bản phát hành bản phát hành. Xem bình luận của tôi dưới đây .. –

5

Bạn nên đọc bài viết này của Vance. Nó đi vào chi tiết về lý do tại sao các phương pháp không phải lúc nào cũng được JIT'er vạch ra ngay cả khi nó trông hoàn toàn rõ ràng rằng chúng nên.

http://blogs.msdn.com/vancem/archive/2008/08/19/to-inline-or-not-to-inline-that-is-the-question.aspx

+0

Đây là bài báo xem xét chi phí nội tuyến: cả thời gian chạy và chi phí compliation (với tiêu điểm GC): http://cs.anu.edu.au/~Steve.Blackburn/pubs/papers/writebarrier-ismm- 2002.pdf –

3

XNA có để nhắm mục tiêu Xbox 360, và JIT trong .NET Compact Framework là không phức tạp như đối tác máy tính để bàn của mình. .NET CF JIT'er sẽ không có các phương thức thuộc tính nội tuyến.

3

Truy cập trường chỉ là tham chiếu bộ nhớ trong khi sử dụng thuộc tính thực sự đang gọi phương thức và bao gồm phí gọi hàm. Lý do sử dụng các thuộc tính thay vì các trường là cách ly mã của bạn khỏi các thay đổi và cung cấp độ chi tiết tốt hơn khi truy cập. Bằng cách không phơi bày trực tiếp trường của bạn, bạn có quyền kiểm soát tốt hơn cách truy cập được thực hiện. Sử dụng các trường tự động cho phép bạn nhận được hành vi getter/setter thường nhưng xây dựng trong khả năng thay đổi điều này mà không cần một sự thay đổi tiếp theo để truyền cho các phần khác của mã.

Ví dụ: giả sử bạn muốn thay đổi mã của mình để quyền truy cập vào trường được kiểm soát bởi vai trò của người dùng hiện tại. Nếu bạn đã tiếp xúc với công khai trường, bạn phải chạm vào từng phần của mã truy cập nó. Việc hiển thị nó thông qua một thuộc tính cho phép bạn sửa đổi mã thuộc tính để thêm yêu cầu mới nhưng không dẫn đến những thay đổi không cần thiết đối với bất kỳ mã nào truy cập vào nó.

Các vấn đề liên quan