Tôi tự hỏi làm thế nào một đoạn mã bị khóa có thể làm chậm mã của tôi mặc dù mã không bao giờ được thực hiện. Dưới đây là ví dụ bên dưới:Làm thế nào để tránh bị chậm lại do mã bị khóa?
public void Test_PerformanceUnit()
{
Stopwatch sw = new Stopwatch();
sw.Start();
Random r = new Random();
for (int i = 0; i < 10000; i++)
{
testRand(r);
}
sw.Stop();
Console.WriteLine(sw.ElapsedTicks);
}
public object testRand(Random r)
{
if (r.Next(1) > 10)
{
lock(this) {
return null;
}
}
return r;
}
Mã này chạy trong ~ 1300ms trên máy của tôi. Nếu chúng ta loại bỏ khối khóa (nhưng giữ cơ thể của nó), chúng ta nhận được 750ms. Gần như gấp đôi, mặc dù mã không bao giờ chạy!
Tất nhiên mã này không làm gì cả. Tôi nhận thấy nó trong khi thêm một số khởi tạo lười biếng trong một lớp nơi mã kiểm tra nếu đối tượng được khởi tạo và nếu không khởi tạo nó. Vấn đề là việc khởi tạo bị khóa và làm chậm mọi thứ ngay cả sau cuộc gọi đầu tiên.
Câu hỏi của tôi là:
- Tại sao điều này xảy ra?
- Làm thế nào để tránh suy thoái
Trừ khi bạn có ý định sử dụng 'khóa' mạnh mẽ - tôi sẽ không thực sự lo lắng về điều đó. – James
Tôi nhận được kết quả tương tự, nhưng đánh dấu là 100 * nano * giây. Cả hai lần chạy phải mất ~ 0ms (nghĩa là nếu bạn in 'sw.ElapseMilliseconds'.)" Chậm "(trong số ~ 0.00006s) có thể do thực tế là' khóa' bao gồm khối 'try/finally' có thể đang được thiết lập khi phương thức được gọi. Thử đặt nội dung 'testRand' vào chính vòng lặp; bạn sẽ thấy gần như * không * chậm lại tại thời điểm đó. – dlev
Bạn đã thử đánh dấu phương thức với 'AggressiveInline' chưa? Có lẽ mã khóa làm cho phương pháp quá lớn đối với nội tuyến bình thường. Các JITter .net inlines sử dụng một heuristic khá câm dựa trên kích thước của mã IL. – CodesInChaos