为建立中文知识库加块砖 ——中科大胡不归
MSDN定义
Spinlock 自旋锁可用于叶级锁,在这种情况 Monitor 下,通过使用、大小或由于垃圾回收压力而隐含的对象分配的成本非常高。 旋转锁定有助于避免阻塞;但是,如果你预计会有大量的阻塞,则可能由于旋转过多而无法使用自旋锁。 当锁的粒度较大且数量较大时,旋转可能非常有利 (例如,链接列表中的每个节点的锁) ,以及锁保持时间始终极短。 通常,在持有自旋锁时,应避免使用以下任何操作:
- 堵塞
- 调用自身可能会阻止的任何内容,
- 同时保留多个自旋锁,
- (接口和虚方法) 进行动态调度的调用,
- 对任何代码进行静态调度调用,而不是任何代码,或
- 分配内存。
示例代码
"Hello World!".PrintGreen();
var spin = new SpinLock(false);
var obj = new object();
long sum1 = 0;
long sum2 = 0;
long sum3 = 0;
// Parallel.for和Parallel.foreach是线程不安全的
var start = DateTime.Now;
Parallel.For(0, 10000000, i =>
{
sum1 += 1;
});
$"耗时:{DateTime.Now.Subtract(start).TotalMilliseconds}ms".PrintMagenta();
//使用SpinLock
start = DateTime.Now;
Parallel.For(0, 10000000, i =>
{
var lockToken = false;
try
{
spin.Enter(ref lockToken);
sum2 += 1;
}
finally
{
if(lockToken) spin.Exit(false);
}
});
$"耗时:{DateTime.Now.Subtract(start).TotalMilliseconds}ms".PrintMagenta();
// 使用lock
start = DateTime.Now;
Parallel.For(0, 10000000, i =>
{
lock (obj)
{
sum3 += 1;
}
});
$"耗时:{DateTime.Now.Subtract(start).TotalMilliseconds}ms".PrintMagenta();
$"sum1的值为:{sum1}".PrintErr();
$"sum1的值为:{sum2}".PrintErr();
$"sum1的值为:{sum3}".PrintErr();
效果演示
显然这种情况下,SpinLock比lock效率高很多。