Насколько дорого стоит блокировка (...), когда блокировка не разрешена?
При просмотре блокировки с двойным проверкой я видел многочисленные рекомендации, чтобы просто пропустить первую проверку и сразу перейти к блокировке и просто проверить, не приняв ее.
Это заставило меня задаться вопросом: lock (this.padlock)
"дешево", когда вы не уверены?
Ответы
Ответ 1
Мы можем проверить его...
Я получаю:
1000000000; 2164 (no lock)
1000000000; 23258 (lock)
21.094ns per lock
код:
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);
}
}
Ответ 2
Согласно этот источник, накладные расходы для блокировки и разблокировки составляют около 20 нс.
Ответ 3
Я написал это очень быстро и не тестировал его, и я отправляю его только для того, чтобы передать общую идею, один подход к условной блокировке, используя методы расширения, делегаты или лямбда-функции. Я также не могу сказать без тестирования, если это будет самопровозглашение, что, безусловно, возможно.
У меня есть код, который работает как в процессах с несколькими потоками, так и в процессах, использующих модель поточного моделирования кооперативного оптоволокна (например, если существует несколько потоков, которые никогда не выполняются асинхронно). В приложении кооперативного режима волокна блокировка бессмысленна и расточительна, поэтому это может быть решением, позволяющим избежать множества беспорядочной логики в каждой точке, где необходимо выполнить блокировку.
// 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