我用下面的代码在ReaderWriterLock上做了一个非常愚蠢的基准测试,其中读取的频率是写入的4倍:

class Program
{
    static void Main()
    {
        ISynchro[] test = { new Locked(), new RWLocked() };

        Stopwatch sw = new Stopwatch();

        foreach ( var isynchro in test )
        {
            sw.Reset();
            sw.Start();
            Thread w1 = new Thread( new ParameterizedThreadStart( WriteThread ) );
            w1.Start( isynchro );

            Thread w2 = new Thread( new ParameterizedThreadStart( WriteThread ) );
            w2.Start( isynchro );

            Thread r1 = new Thread( new ParameterizedThreadStart( ReadThread ) );
            r1.Start( isynchro );

            Thread r2 = new Thread( new ParameterizedThreadStart( ReadThread ) );
            r2.Start( isynchro );

            w1.Join();
            w2.Join();
            r1.Join();
            r2.Join();
            sw.Stop();

            Console.WriteLine( isynchro.ToString() + ": " + sw.ElapsedMilliseconds.ToString() + "ms." );
        }

        Console.WriteLine( "End" );
        Console.ReadKey( true );
    }

    static void ReadThread(Object o)
    {
        ISynchro synchro = (ISynchro)o;

        for ( int i = 0; i < 500; i++ )
        {
            Int32? value = synchro.Get( i );
            Thread.Sleep( 50 );
        }
    }

    static void WriteThread( Object o )
    {
        ISynchro synchro = (ISynchro)o;

        for ( int i = 0; i < 125; i++ )
        {
            synchro.Add( i );
            Thread.Sleep( 200 );
        }
    }

}

interface ISynchro
{
    void Add( Int32 value );
    Int32? Get( Int32 index );
}

class Locked:List<Int32>, ISynchro
{
    readonly Object locker = new object();

    #region ISynchro Members

    public new void Add( int value )
    {
        lock ( locker ) 
            base.Add( value );
    }

    public int? Get( int index )
    {
        lock ( locker )
        {
            if ( this.Count <= index )
                return null;
            return this[ index ];
        }
    }

    #endregion
    public override string ToString()
    {
        return "Locked";
    }
}

class RWLocked : List<Int32>, ISynchro
{
    ReaderWriterLockSlim locker = new ReaderWriterLockSlim();

    #region ISynchro Members

    public new void Add( int value )
    {
        try
        {
            locker.EnterWriteLock();
            base.Add( value );
        }
        finally
        {
            locker.ExitWriteLock();
        }
    }

    public int? Get( int index )
    {
        try
        {
            locker.EnterReadLock();
            if ( this.Count <= index )
                return null;
            return this[ index ];
        }
        finally
        {
            locker.ExitReadLock();
        }
    }

    #endregion

    public override string ToString()
    {
        return "RW Locked";
    }
}

但我知道两者的表现大同小异:

Locked: 25003ms.
RW Locked: 25002ms.
End

即使读的次数比写的次数多20倍,性能仍然(几乎)相同.

我做错什么了吗?

亲切的问候.

推荐答案

在你的例子中,睡眠意味着没有争用.没有竞争的锁非常快.要做到这一点,你需要一把contended锁;如果该争用中有writes个,它们应该大致相同(lock个可能更快),但如果是mostly个读取(很少有写争用),我希望ReaderWriterLockSlim锁执行lock个.

就我个人而言,我在这里更喜欢另一种策略,使用引用交换-这样读操作总是可以读取,而不需要判断/锁定/等等.写操作将其更改为cloned副本,然后使用Interlocked.CompareExchange来交换引用(如果另一个线程在过渡期间改变了引用,则重新应用它们的更改).

.net相关问答推荐

创建仅包含msBuild.Target的Nuget包

Npgsql Minimum Pool Size 似乎没有被考虑在内

如何找到windows服务exe路径

"投掷;" 是什么意思?靠自己做什么?

如何在 FtpWebRequest 之前判断 FTP 上是否存在文件

Environment.TickCount 与 DateTime.Now

如何在 EF 代码优先中禁用链接表的级联删除?

app.config 文件和 XYZ.settings 文件有什么区别?

如何使用c#从excel文件中读取数据

读取方法的属性值

VB.NET 与 C# 整数除法

使用 C# 设置全局热键

场与财产.性能优化

如何从文件中删除单个属性(例如只读)?

MemoryCache 不遵守配置中的内存限制

System.Array.CopyTo() 和 System.Array.Clone() 之间的区别

C# ListView 列宽自动

多个列表与 IEnumerable.Intersect() 的交集

我可以为 Dictionary 条目使用集合初始化程序吗?

从 bcp 客户端接收到 colid 6 的无效列长度