为什么 lock 比 ReaderWriterLockSlim 快 240%?
Why lock is 240% faster than ReaderWriterLockSlim?
我读了另一个 SO 问题:When is ReaderWriterLockSlim better than a simple lock?
而且它并不能准确解释为什么 ReaderWriterLockSlim
比 lock
慢。
我的测试是肯定的 - 零争用测试,但仍然无法解释惊人的差异。
读锁耗时2.7s,写锁2.2s,加锁1.0s
这是完整的代码:
using System;
using System.Diagnostics;
using System.Threading;
namespace test
{
internal class Program
{
static int[] data = new int[100000000];
static object lock1 = new object();
static ReaderWriterLockSlim lock2 = new ReaderWriterLockSlim();
static void Main(string[] args)
{
for (int z = 0; z < 3; z++)
{
var sw = Stopwatch.StartNew();
for (int i = 0; i < data.Length; i++)
{
lock (lock1)
{
data[i] = i;
}
}
sw.Stop();
Console.WriteLine("Lock: {0}", sw.Elapsed);
sw.Restart();
for (int i = 0; i < data.Length; i++)
{
try
{
lock2.EnterReadLock();
data[i] = i;
}
finally
{
lock2.ExitReadLock();
}
}
sw.Stop();
Console.WriteLine("Read: {0}", sw.Elapsed);
sw.Restart();
for (int i = 0; i < data.Length; i++)
{
try
{
lock2.EnterWriteLock();
data[i] = i;
}
finally
{
lock2.ExitWriteLock();
}
}
sw.Stop();
Console.WriteLine("Write: {0}\n", sw.Elapsed);
}
Console.ReadKey(false);
}
}
}
您正在查看两个设备。左边是一个lock
. At the right is a ReaderWriterLockSlim
.
左边的设备用于从一个位置控制单个电动装置 lamp。右边的设备用于从两个不同的位置控制两个 lamp。¹ 左边的设备购买更便宜,需要的接线更少,安装和操作更简单,并且能量损失更少由于热量比右边的设备。
与 SPST/DPDT electric switches 的类比可能远非完美,但我的观点是 lock
是一种比 ReaderWriterLockSlim
相对简单的机制。它用于对同质工作线程组实施单一策略。另一方面,ReaderWriterLockSlim
用于对两个不同的工作组(读者和作者)执行两种不同的策略,关于他们如何与同一组和另一组的成员交互。毫不奇怪,更复杂的机制比更简单的机制具有更高的运营成本(开销)。这是为了更好地控制工作线程而必须付出的代价。
¹ 也许不是。我不是电工!
感谢@canton 和@KevinGosse - 我发现 @HansPassant 完美地回答了我 2013 年的问题:When exactly does .NET Monitor go to kernel-mode?
所以锁在 no-contention 场景中更快只是因为它有更轻的逻辑并且不涉及内核模式。
我读了另一个 SO 问题:When is ReaderWriterLockSlim better than a simple lock?
而且它并不能准确解释为什么 ReaderWriterLockSlim
比 lock
慢。
我的测试是肯定的 - 零争用测试,但仍然无法解释惊人的差异。
读锁耗时2.7s,写锁2.2s,加锁1.0s
这是完整的代码:
using System;
using System.Diagnostics;
using System.Threading;
namespace test
{
internal class Program
{
static int[] data = new int[100000000];
static object lock1 = new object();
static ReaderWriterLockSlim lock2 = new ReaderWriterLockSlim();
static void Main(string[] args)
{
for (int z = 0; z < 3; z++)
{
var sw = Stopwatch.StartNew();
for (int i = 0; i < data.Length; i++)
{
lock (lock1)
{
data[i] = i;
}
}
sw.Stop();
Console.WriteLine("Lock: {0}", sw.Elapsed);
sw.Restart();
for (int i = 0; i < data.Length; i++)
{
try
{
lock2.EnterReadLock();
data[i] = i;
}
finally
{
lock2.ExitReadLock();
}
}
sw.Stop();
Console.WriteLine("Read: {0}", sw.Elapsed);
sw.Restart();
for (int i = 0; i < data.Length; i++)
{
try
{
lock2.EnterWriteLock();
data[i] = i;
}
finally
{
lock2.ExitWriteLock();
}
}
sw.Stop();
Console.WriteLine("Write: {0}\n", sw.Elapsed);
}
Console.ReadKey(false);
}
}
}
您正在查看两个设备。左边是一个lock
. At the right is a ReaderWriterLockSlim
.
左边的设备用于从一个位置控制单个电动装置 lamp。右边的设备用于从两个不同的位置控制两个 lamp。¹ 左边的设备购买更便宜,需要的接线更少,安装和操作更简单,并且能量损失更少由于热量比右边的设备。
与 SPST/DPDT electric switches 的类比可能远非完美,但我的观点是 lock
是一种比 ReaderWriterLockSlim
相对简单的机制。它用于对同质工作线程组实施单一策略。另一方面,ReaderWriterLockSlim
用于对两个不同的工作组(读者和作者)执行两种不同的策略,关于他们如何与同一组和另一组的成员交互。毫不奇怪,更复杂的机制比更简单的机制具有更高的运营成本(开销)。这是为了更好地控制工作线程而必须付出的代价。
¹ 也许不是。我不是电工!
感谢@canton 和@KevinGosse - 我发现 @HansPassant 完美地回答了我 2013 年的问题:When exactly does .NET Monitor go to kernel-mode?
所以锁在 no-contention 场景中更快只是因为它有更轻的逻辑并且不涉及内核模式。