C# 使用相同的代码实现时,无法模拟ConcurrentStack的性能

C# 使用相同的代码实现时,无法模拟ConcurrentStack的性能,c#,.net,multithreading,ilspy,C#,.net,Multithreading,Ilspy,我正在学习编写并发数据结构,并将ConcurrentStack实现作为一项学习练习。首先,我创建了一个ConcurrentStack实现的副本,使用IlSpy将其反编译为C。目前我仅限于研究和使用Push和TryPop方法 但是我的实现要比使用原始版本慢得多 我的测试使用了4个线程(在一个套接字上,4个核心CPU),每个线程对不同的核心具有线程亲和力。每个线程执行1000000个循环,每个循环执行三次推送和三次弹出。多次运行测试完成所有线程的平均时间是 ConcurrentStack=>445

我正在学习编写并发数据结构,并将ConcurrentStack实现作为一项学习练习。首先,我创建了一个ConcurrentStack实现的副本,使用IlSpy将其反编译为C。目前我仅限于研究和使用Push和TryPop方法

但是我的实现要比使用原始版本慢得多

我的测试使用了4个线程(在一个套接字上,4个核心CPU),每个线程对不同的核心具有线程亲和力。每个线程执行1000000个循环,每个循环执行三次推送和三次弹出。多次运行测试完成所有线程的平均时间是

  • ConcurrentStack=>445ms
  • Push/TryPop的克隆=>670ms
因此,即使代码,据我所知,在两者之间是相同的,克隆大约要慢50%。我一次运行500次测试,并取所有运行的平均值。所以我不认为问题在于代码的初始JIT

你知道为什么复制这些方法会慢得多吗

C#实施

(为了完整性起见,我提供了可用于复制结果的C#console应用程序代码。供有兴趣了解他们是否获得与我相同的结果的人使用。)

类程序
{
静态void Main(字符串[]参数)
{
int processors=Environment.ProcessorCount;
WriteLine(“处理器:{0}”,处理器);
List runnersT=new List(){typeof(ThreadRunnerConcurrent),
类型(ThreadRunnerCASStack)};
int循环=500;
foreach(在runnersT中输入runnerT)
{
长总计=0;
对于(int i=0;ir.Start());
//等待所有跑步者退出
ForEach((r)=>r.Join());
ForEach((r)=>r.Check());
sw.Stop();
总+=sw.ElapsedMilliseconds;
}
WriteLine(“{0}平均:{1}ms”,runnerT.Name,(总数/周期));
}
控制台。写入线(“完成”);
Console.ReadLine();
}
}
抽象类ThreadRunner
{
专用int_处理器;
私有线程(u线程),;
公共ThreadRunner()
{
}
公共整数处理器
{
获取{return\u processor;}
设置{u处理器=值;}
}
公开作废开始()
{
_线程=新线程(新参数化线程启动(运行));
_thread.Start();
}
公共void Join()
{
_thread.Join();
}
公共摘要无效检查();
受保护的抽象无效运行(整数周期);
私有无效运行(对象参数)
{
SetAffinity();
运行(1000000);
}
私有void SetAffinity()
{
#pragma警告禁用618
int-osThreadId=AppDomain.GetCurrentThreadId();
#pragma警告恢复618
//设置线程的处理器关联
ProcessThread thread=Process.GetCurrentProcess().Threads.Cast().Where(t=>t.Id==osThreadId).Single();
thread.ProcessorAffinity=新的IntPtr(1L 0)
WriteLine(“ThreadRunnerConcurrent有条目!”);
}
}
类ThreadRunnerCASStack:ThreadRunner
{
私有静态CASStack _stack=new CASStack();
受保护的覆盖无效运行(整数周期)
{
int ret;
对于(int i=0;i0)
WriteLine(“ThreadRunnerCASStack有条目!”);
}
}
类卡斯塔克
{
私有类节点
{
内部只读T m_值;
内部CASStack.Node m_next;
内部节点(T值)
{
此m_值=值;
this.m_next=null;
}
}
私有易失性CASStack.Node m_head;
公共无效推送(T项)
{
CASStack.Node节点=新CASStack.Node(项目);
node.m_next=这个.m_头;
if(interlocated.compareeexchange(ref this.m_head,node,node.m_next)=node.m_next)
返回;
PushCore(节点,节点);
}
专用空心推芯(节点头、节点尾)
{
SpinWait SpinWait=默认值(SpinWait);
做
{
spinWait.SpinOnce();
tail.m_next=这个.m_头;
}
while(interlocated.compareeexchange(参考this.m_head,head,tail.m_next)!=tail.m_next);
}
公共bool TryPop(out T结果)
{
CASStack.Node head=此.m_head;
if(head==null)
{
结果=默认值(T);
返回false;
}
if(联锁比较交换(参考this.m_head,head.m_next,head)=head)
{
结果=head.m_值;
返回true;
}
返回TryPopCore(输出结果);
}
私有布尔锥波积核(输出T结果)
{
卡斯塔克节点;
if(TryPopCore(1,out节点)==1)
{
结果=node.m_值;
class Program
{
    static void Main(string[] args)
    {
        int processors = Environment.ProcessorCount;
        Console.WriteLine("Processors: {0}", processors);

        List<Type> runnersT = new List<Type>() { typeof(ThreadRunnerConcurrent), 
                                                 typeof(ThreadRunnerCASStack)};
        int cycles = 500;
        foreach (Type runnerT in runnersT)
        {
            long total = 0;
            for (int i = 0; i < cycles; i++)
            {
                // Create a thread runner per processor
                List<ThreadRunner> runners = new List<ThreadRunner>();
                for (int j = 0; j < processors; j++)
                {
                    ThreadRunner runner = Activator.CreateInstance(runnerT) as ThreadRunner;
                    runner.Processor = j;
                    runners.Add(runner);
                }

                // Start each runner going
                Stopwatch sw = new Stopwatch();
                sw.Start();
                runners.ForEach((r) => r.Start());

                // Wait for all the runners to exit
                runners.ForEach((r) => r.Join());
                runners.ForEach((r) => r.Check());
                sw.Stop();

                total += sw.ElapsedMilliseconds;
            }

            Console.WriteLine("{0} Average: {1}ms", runnerT.Name, (total / cycles));
        }

        Console.WriteLine("Finished");
        Console.ReadLine();
    }
}

abstract class ThreadRunner
{
    private int _processor;
    private Thread _thread;

    public ThreadRunner()
    {
    }

    public int Processor
    {
        get { return _processor; }
        set { _processor = value; }
    }

    public void Start()
    {
        _thread = new Thread(new ParameterizedThreadStart(Run));
        _thread.Start();
    }

    public void Join()
    {
        _thread.Join();
    }

    public abstract void Check();

    protected abstract void Run(int cycles);

    private void Run(object param)
    {
        SetAffinity();
        Run(1000000);
    }

    private void SetAffinity()
    {
        #pragma warning disable 618
        int osThreadId = AppDomain.GetCurrentThreadId();
        #pragma warning restore 618

        // Set the thread's processor affinity
        ProcessThread thread = Process.GetCurrentProcess().Threads.Cast<ProcessThread>().Where(t => t.Id == osThreadId).Single();
        thread.ProcessorAffinity = new IntPtr(1L << Processor);
    }
}

class ThreadRunnerConcurrent : ThreadRunner
{
    private static ConcurrentStack<int> _stack = new ConcurrentStack<int>();

    protected override void Run(int cycles)
    {
        int ret;
        for (int i = 0; i < cycles; i++)
        {
            _stack.Push(i);
            _stack.Push(i);
            while (!_stack.TryPop(out ret)) ;
            _stack.Push(i);
            while (!_stack.TryPop(out ret)) ;
            while (!_stack.TryPop(out ret)) ;
        }
    }

    public override void Check()
    {
        if (_stack.Count > 0)
            Console.WriteLine("ThreadRunnerConcurrent has entries!");
    }
}

class ThreadRunnerCASStack : ThreadRunner
{
    private static CASStack<int> _stack = new CASStack<int>();

    protected override void Run(int cycles)
    {
        int ret;
        for (int i = 0; i < cycles; i++)
        {
            _stack.Push(i);
            _stack.Push(i);
            while (!_stack.TryPop(out ret)) ;
            _stack.Push(i);
            while (!_stack.TryPop(out ret)) ;
            while (!_stack.TryPop(out ret)) ;
        }
    }

    public override void Check()
    {
        if (_stack.Count > 0)
            Console.WriteLine("ThreadRunnerCASStack has entries!");
    }
}

class CASStack<T>
{
    private class Node
    {
        internal readonly T m_value;
        internal CASStack<T>.Node m_next;
        internal Node(T value)
        {
            this.m_value = value;
            this.m_next = null;
        }
    }

    private volatile CASStack<T>.Node m_head;

    public void Push(T item)
    {
        CASStack<T>.Node node = new CASStack<T>.Node(item);
        node.m_next = this.m_head;

        if (Interlocked.CompareExchange<CASStack<T>.Node>(ref this.m_head, node, node.m_next) == node.m_next)
            return;

        PushCore(node, node);
    }

    private void PushCore(Node head, Node tail)
    {
        SpinWait spinWait = default(SpinWait);

        do
        {
            spinWait.SpinOnce();
            tail.m_next = this.m_head;
        }
        while (Interlocked.CompareExchange<CASStack<T>.Node>(ref this.m_head, head, tail.m_next) != tail.m_next);
    }

    public bool TryPop(out T result)
    {
        CASStack<T>.Node head = this.m_head;

        if (head == null)
        {
            result = default(T);
            return false;
        }

        if (Interlocked.CompareExchange<CASStack<T>.Node>(ref this.m_head, head.m_next, head) == head)
        {
            result = head.m_value;
            return true;
        }

        return TryPopCore(out result);
    }

    private bool TryPopCore(out T result)
    {
        CASStack<T>.Node node;
        if (TryPopCore(1, out node) == 1)
        {
            result = node.m_value;
            return true;
        }
        result = default(T);
        return false;
    }

    private int TryPopCore(int count, out CASStack<T>.Node poppedHead)
    {
        SpinWait spinWait = default(SpinWait);
        int num = 1;
        Random random = new Random(Environment.TickCount & 2147483647);
        CASStack<T>.Node head;
        int num2;
        while (true)
        {
            head = this.m_head;
            if (head == null)
                break;

            CASStack<T>.Node node = head;
            num2 = 1;
            while (num2 < count && node.m_next != null)
            {
                node = node.m_next;
                num2++;
            }

            if (Interlocked.CompareExchange<CASStack<T>.Node>(ref this.m_head, node.m_next, head) == head)
                goto Block_5;

            for (int i = 0; i < num; i++)
                spinWait.SpinOnce();

            num = (spinWait.NextSpinWillYield ? random.Next(1, 8) : (num * 2));
        }
        poppedHead = null;
        return 0;
    Block_5:
        poppedHead = head;
        return num2;
    }
}
#endregion
Processors: 4
ThreadRunnerConcurrent Average: 764ms
ThreadRunnerCASStack Average: 948ms
Finished
Processors: 4
ThreadRunnerConcurrent Average: 778ms
ThreadRunnerCASStack Average: 742ms
Finished