首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么InterLocked比锁慢?

为什么InterLocked比锁慢?
EN

Stack Overflow用户
提问于 2016-05-10 07:43:48
回答 1查看 1.7K关注 0票数 0

出于好奇,我编写了一个程序来测试InterLocked与.Net锁的性能。事实证明,InterLocked版本比锁定版本慢得多,请有人指出如果我在这里遗漏了一些细节。根据我的理解,互锁应该比锁好得多。

代码语言:javascript
复制
public class TestB
    {
        private static readonly object _objLocker = new object();
        private long _shared;
        public void IncrLocked()
        {
            lock (_objLocker)
            {
                _shared++;
            }
        }
        public void IncrInterLocked()
        {
            Interlocked.Increment(ref _shared);
        }
        public long GetValue()
        {
            return _shared;
        }
    }
    class TestsCopy
    {
        private static TestB _testB = new TestB();
        static void Main(string[] args)
        {
            int numofthreads = 100;
            TestInterLocked(numofthreads);
            TestLocked(numofthreads);
            Console.ReadLine();
        }
        private static void TestInterLocked(int numofthreads)
        {
            Thread[] threads = new Thread[numofthreads];
            for (int i = 0; i < numofthreads; i++)
            {
                Thread t = new Thread(StartTestInterLocked);
                threads[i] = t;
                t.Start();
            }
            Stopwatch sw = new Stopwatch();
            sw.Start();
            for (int i = 0; i < threads.Length; i++)
            {
                threads[i].Join();
            }
            sw.Stop();
            Console.WriteLine($"Interlocked finished in : {sw.ElapsedMilliseconds}, value = {_testB.GetValue()}");
        }

        private static void TestLocked(int numofthreads)
        {
            Thread[] threads = new Thread[numofthreads];
            for (int i = 0; i < numofthreads; i++)
            {
                Thread t = new Thread(StartTestLocked);
                threads[i] = t;
                t.Start();
            }
            Stopwatch sw = new Stopwatch();
            sw.Start();
            for (int i = 0; i < threads.Length; i++)
            {
                threads[i].Join();
            }
            sw.Stop();
            Console.WriteLine($"Locked finished in : {sw.ElapsedMilliseconds}, value = {_testB.GetValue()}");
        }

        private static void StartTestInterLocked()
        {
            int counter = 10000000;
            for (int i = 0; i < counter; i++)
            {
                _testB.IncrInterLocked();
            }
        }
        private static void StartTestLocked()
        {
            int counter = 10000000;
            for (int i = 0; i < counter; i++)
            {
                _testB.IncrLocked();
            }
        }

程序的输出是..。

代码语言:javascript
复制
Interlocked finished in : 76909 ms, value = 1000000000
Locked finished in : 44215 ms, value = 2000000000
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-05-10 08:05:38

由于Jakob提到的原因,您的测试是有缺陷的。此外,您的测试还包括在类中调用方法的开销(对于lock,显然这是调用Interlocked.Increment()时无法避免的)。

您应该启动所有线程,并安排它们在启动秒表后开始工作。您可以通过让他们在ManualResetEvent上等待来做到这一点。

我重写了您的测试代码如下:

代码语言:javascript
复制
using System;
using System.Diagnostics;
using System.Threading;

namespace Demo
{
    static class Program
    {
        private static readonly object _objLocker = new object();
        private static long _shared;
        private static ManualResetEvent _signal = new ManualResetEvent(false);

        static void Main(string[] args)
        {
            int numofthreads = 100;
            TestInterLocked(numofthreads);
            TestLocked(numofthreads);
            Console.ReadLine();
        }

        private static void TestInterLocked(int numofthreads)
        {
            Thread[] threads = new Thread[numofthreads];
            for (int i = 0; i < numofthreads; i++)
            {
                Thread t = new Thread(StartTestInterLocked);
                threads[i] = t;
                t.Start();
            }
            Thread.Sleep(5000); // Make sure threads have had time to start.
            Stopwatch sw = new Stopwatch();
            sw.Start();
            _shared = 0;
            _signal.Set();

            for (int i = 0; i < threads.Length; i++)
            {
                threads[i].Join();
            }

            sw.Stop();
            _signal.Reset();
            Console.WriteLine($"Interlocked finished in : {sw.ElapsedMilliseconds}, value = {_shared}");
        }

        private static void TestLocked(int numofthreads)
        {
            Thread[] threads = new Thread[numofthreads];
            for (int i = 0; i < numofthreads; i++)
            {
                Thread t = new Thread(StartTestLocked);
                threads[i] = t;
                t.Start();
            }
            Thread.Sleep(5000); // Make sure threads have had time to start.
            Stopwatch sw = new Stopwatch();
            sw.Start();
            _shared = 0;
            _signal.Set();

            for (int i = 0; i < threads.Length; i++)
            {
                threads[i].Join();
            }

            sw.Stop();
            _signal.Reset();
            Console.WriteLine($"Locked finished in : {sw.ElapsedMilliseconds}, value = {_shared}");
        }

        private static void StartTestInterLocked()
        {
            _signal.WaitOne();
            int counter = 10000000;
            for (int i = 0; i < counter; i++)
            {
                Interlocked.Increment(ref _shared);
            }
        }

        private static void StartTestLocked()
        {
            _signal.WaitOne();
            int counter = 10000000;
            for (int i = 0; i < counter; i++)
            {
                lock (_objLocker)
                {
                    _shared++;
                }
            }
        }
    }
}

现在的结果是(来自发行版构建):

代码语言:javascript
复制
Interlocked finished in : 11339, value = 1000000000
Locked finished in : 30546, value = 1000000000

如您所见,Interlocked的速度要快得多。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/37132209

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档