2012-01-09 32 views
22

Trong khi nhìn vào khóa kiểm tra kép, tôi đã thấy nhiều khuyến nghị chỉ cần bỏ qua kiểm tra đầu tiên và ngay lập tức đi đến khóa và chỉ cần kiểm tra sau khi dùng nó thay thế.Khóa đắt bao nhiêu (...) khi khóa không bị khóa?

Điều này khiến tôi tự hỏi, là lock (this.padlock) "rẻ" khi không được kiểm soát?

+1

Trong quyết định này, bạn cũng phải đánh giá: khóa sẽ không bị phát hiện (ví dụ: mức độ xảy ra ** bên trong ** khóa sẽ làm tăng đáng kể tỷ lệ tranh chấp). Tùy thuộc vào kịch bản, có thể tốt hơn để thực hiện kiểm tra chính hãng đôi hoặc bạn có thể không khóa. Kể từ khi tài liệu tham khảo được đảm bảo nguyên tử, di chuyển dữ liệu đến một đối tượng bất biến và dereferencing nó có thể được khá dễ thương (trong kịch bản bên phải). –

Trả lời

24

Chúng ta có thể kiểm tra nó ...

tôi nhận được:

1000000000; 2164 (no lock) 
1000000000; 23258 (lock) 
21.094ns per lock 

Code:

using System; 
using System.Diagnostics; 

static class P 
{ 
    static void Main() 
    { 

     Test(1); // for JIT 
     Test(1000000); 
    } 
    static readonly object syncLock = new object(); 
    static void Test(int count) 
    { 
     int j = 0; 
     var watch = Stopwatch.StartNew(); 
     for(int i = 0 ; i < count ; i++) 
     { 
      for (int z = 0; z < 1000; z++) 
       j++; 
     } 
     watch.Stop(); 
     long withoutMillis = watch.ElapsedMilliseconds; 
     Console.WriteLine("{0}; {1} (no lock)", j, watch.ElapsedMilliseconds); 

     j = 0; 
     watch = Stopwatch.StartNew(); 
     for (int i = 0; i < count; i++) 
     { 
      for (int z = 0; z < 1000; z++) 
       lock (syncLock) 
       { 
        j++; 
       } 
     } 
     watch.Stop(); 
     long withMillis = watch.ElapsedMilliseconds; 
     Console.WriteLine("{0}; {1} (lock)", j, watch.ElapsedMilliseconds); 

     long deltaNano = (withMillis - withoutMillis) * 1000000; 
       // nano = 1000 micro = 1000000 milli 
     double perLockNano = deltaNano/(1000.0 * count); 
     Console.WriteLine("{0}ns per lock", perLockNano); 
    } 
} 
+0

HW của bạn là gì? –

+0

@JohannGerell Intel i7 quad 920 @ 2,67 GHz, chạy x64 .NET 4 trên Win7 –

+0

@JohannGerell cũng lưu ý rằng tôi đang thực hiện 'ldsfld' (' lock (staticLockObject) '), thay vì' ldarg0 + ldfld' (' khóa (this.instanceLockObject) ') - bạn sẽ có thể điều chỉnh thử nghiệm để cho phép điều đó. –

10

Theo this source, chi phí để khóa và mở khóa khoảng 20ns.

+4

Và có, đó là (rất) giá rẻ. –

2

tôi đã viết này rất nhanh chóng và đã không kiểm tra nó, và tôi chỉ đăng tải nó để truyền tải ý tưởng chung, của một phương pháp tiếp cận khóa có điều kiện, sử dụng các phương thức mở rộng, và các đại biểu hoặc hàm lambda. Tôi cũng không thể nói mà không cần kiểm tra, nếu điều này có thể tự đánh bại, điều chắc chắn là có thể.

Tôi có mã chạy trong cả hai quy trình đa luồng và quy trình sử dụng mô hình luồng chế độ sợi hợp tác (ví dụ: nơi có nhiều luồng không bao giờ thực thi không đồng bộ). Trong ứng dụng chế độ sợi hợp tác, khóa là vô nghĩa và lãng phí, vì vậy đây có thể là một giải pháp để tránh rất nhiều logic lộn xộn tại mỗi điểm mà khóa phải được thực hiện.

// Conditional Locking concept code 

namespace SystemExtensions { 

public static class LockMeUp 
{ 
    private static bool isLockingEnabled = true; 

    // If set to true, locking will be performed 
    // by the extension methods below. 

    internal static bool LockingEnabled 
    { 
    get 
    { 
     return isLockingEnabled; 
    } 
    set 
    { 
     isLockingEnbaled = value; 
    } 
    } 

    static void CheckNull<TLock>(TLock target) where TLock: class 
    { 
    if(target == null) 
     throw new ArgumentNullException("target cannot be null"); 
    } 

    // Invoke the supplied action on the supplied lock object 

    public static void TryLock<TLock>( 
    this TLock target, 
    Action<TLock> action) where TLock: class 
    { 
    CheckNull(target); 
    if(isLockingEnabled) 
    { 
     lock(target) 
     { 
     action(target); 
     } 
    } 
    else 
    { 
     action(target); 
    } 
    } 

    // Invoke the supplied function on the supplied 
    // lock object and return result: 

    public static T TryLock<TLock, T>( 
    this TLock target, 
    Func<TLock, T> func) where TLock: class 
    { 
    CheckNull(target); 
    if(isLockingEnabled) 
    { 
     lock(target) 
     { 
     return func(target); 
     } 
    } 
    else 
    { 
     return func(target); 
    } 
    } 

    // Invoke the supplied function on the supplied lock object 
    // and another supplied argument, and return the result:  

    public static T TryLock<TLock, TArg, T>( 
    this TLock target, 
    Func<TLock, TArg, T> func, 
    TArg arg) where TLock: class 
    { 
    CheckNull(target); 
    if(isLockingEnabled) 
    { 
     lock(target) 
     { 
     return func(target, arg); 
     } 
    } 
    else 
    { 
     return func(target, arg); 
    } 
    } 

    // Invoke the supplied action on the supplied lock object 
    // and another supplied argument: 

    public static void TryLock<TLock, TArg>( 
    this TLock target, 
    Action<TLock, TArg> func, 
    TArg arg) where TLock: class 
    { 
    CheckNull(target); 
    if(isLockingEnabled) 
    { 
     lock(target) 
     { 
     func(target, arg); 
     } 
    } 
    else 
    { 
     func(target, arg); 
    } 
    } 
} 

///// Example: 

public static class SharedList<T> 
{ 
    private static List<T> items = new List<T>(); 

    public static bool Remove(T item) 
    { 
    return items.TryLock((list, item) => list.Remove(item), item); 
    } 

    public static T GetItemAt(int index) 
    { 
    return items.TryLock((list, i) => list[i], index); 
    } 

    public static bool Contains(T item) 
    { 
    return items.TryLock((list, it) => list.Contains(it), item); 
    } 

    public static void Add(T item) 
    { 
    items.TryLock((list, item) => list.Add(item)); 
    } 
} 

} // namespace 
Các vấn đề liên quan