Tôi đã xem qua một sự khác biệt về tốc độ bằng cách sử dụng hai cấu trúc sau:hiệu suất constructor tĩnh và lý do tại sao chúng tôi không thể xác định beforefieldinit
public struct NoStaticCtor
{
private static int _myValue = 3;
public static int GetMyValue() { return _myValue; }
}
public struct StaticCtor
{
private static int _myValue;
public static int GetMyValue() { return _myValue; }
static StaticCtor()
{
_myValue = 3;
}
}
class Program
{
static void Main(string[] args)
{
long numTimes = 5000000000; // yup, 5 billion
Stopwatch sw = new Stopwatch();
sw.Start();
for (long i = 0; i < numTimes; i++)
{
NoStaticCtor.GetMyValue();
}
sw.Stop();
Console.WriteLine("No static ctor: {0}", sw.Elapsed);
sw.Restart();
for (long i = 0; i < numTimes; i++)
{
StaticCtor.GetMyValue();
}
sw.Stop();
Console.WriteLine("with static ctor: {0}", sw.Elapsed);
}
}
nào tạo ra kết quả:
Release (x86), no debugger attached:
No static ctor: 00:00:05.1111786
with static ctor: 00:00:09.9502592
Release (x64), no debugger attached:
No static ctor: 00:00:03.2595979
with static ctor: 00:00:14.5922220
Trình biên dịch tạo ra một constructor tĩnh cho NoStaticCtor
giống hệt với khai báo một cách rõ ràng trong StaticCtor
. Tôi hiểu rằng trình biên dịch sẽ chỉ phát ra beforefieldinit
khi một hàm tạo tĩnh không được định nghĩa rõ ràng.
Họ sản xuất gần đang il giống hệt nhau, ngoại trừ một sự khác biệt, tuyên bố struct với beforefieldinit
, đó là nơi tôi cảm thấy sự khác biệt nằm kể từ khi tôi biết nó quyết định khi các nhà xây dựng loại được gọi là, mặc dù tôi có thể không hoàn toàn tìm ra lý do tại sao có sự khác biệt như vậy. Giả sử nó không phải là gọi kiểu hàm tạo mỗi lần lặp lại, vì một hàm tạo kiểu chỉ có thể được gọi một lần.
Vì vậy,
1) Tại sao sự khác biệt về thời gian giữa struct với beforefieldinit
và một mà không có? (Tôi tưởng tượng JITer đang làm một cái gì đó thêm trong vòng lặp, tuy nhiên, tôi không có đầu mối làm thế nào để xem đầu ra của JITer để xem những gì.
2) Tại sao các nhà thiết kế trình biên dịch) không làm cho tất cả các cấu trúc beforefieldinit
mặc định và b) không cung cấp cho nhà phát triển khả năng xác định rõ hành vi đó? Tất nhiên, điều này là giả sử bạn không thể, vì tôi đã không thể tìm thấy một cách.
Edit:
. I modified the code, về cơ bản chạy mỗi vòng lặp lần thứ hai, mong đợi một sự cải thiện, nhưng nó đã không nhiều:
No static ctor: 00:00:03.3342359
with static ctor: 00:00:14.6139917
No static ctor: 00:00:03.2229995
with static ctor: 00:00:12.9524860
Press any key to continue . . .
Tôi đã làm điều này vì tôi, mặc dù tốt, lẽ, tuy nhiên không chắc nó là, JITer đã thực sự gọi hàm tạo kiểu mỗi lần lặp lại. Dường như với tôi JITer sẽ biết constructor kiểu đã được gọi và không phát ra mã để làm điều đó khi vòng lặp thứ hai được biên dịch.
Ngoài câu trả lời Motti của: This code tạo ra kết quả tốt hơn, vì sự khác biệt trong JITing, các JITing của DoSecondLoop
không phát ra kiểm tra ctor tĩnh, bởi vì nó phát hiện nó đã được thực hiện trước đó trong DoFirstLoop
, khiến mỗi vòng lặp để thực hiện ở cùng một tốc độ. (~ 3 giây)
Một số quan điểm về số lượng lớn là bắt buộc tại đây. Chi phí bạn đo được là * một nano giây *. Có, đó là về những gì một hướng dẫn thử nghiệm nhảy + mất. –
@Tôi biết chi phí rất nhỏ. Tôi sẽ không bao giờ thực sự viết mã như thế này được sử dụng trong sản xuất. Tôi hiện đang trên một "làm thế nào để CLR làm việc" stint và tôi đã rối tung xung quanh với những điều bất thường. Tôi thực sự chỉ cố gắng hiểu tại sao JITer đưa ra quyết định, dựa trên các thuộc tính mà trình biên dịch phát ra. Có lẽ tôi nên mua một cuốn sách. –