WaitHandle同步有多贵?

时间:2015-10-30 16:32:59

标签: c# performance synchronization

我听说WaitHandle派生的同步原语价格昂贵,但无法找到更多细节。是否有其他等效或类似原语的性能比较?

1 个答案:

答案 0 :(得分:0)

对于一个特殊情况,AutoResetEventMonitor可以互换,监视器的性能至少提高1.5倍(通常为2倍)。此声明基于以下原始生产者/消费者测试(发布版本),并且在测试逻辑中没有错误的情况下有效:o)无论如何,可能对某人有用...

现在,我试图成为the one who races the horses;)

代码:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using Timer = System.Timers.Timer;

namespace ThreadSync2
{
    static class Measurement
    {
        private static readonly Random rng = new Random();

        private static long Evaluate(string methodName, Action signal, Action wait)
        {
            var isProducing = false;
            var isConsuming = false;
            var mtxData     = new object(); 
            var data        = new Queue<Tuple<long,int>>();
            var produced    = 0L;
            var consumed    = 0L;
            var watch       = new Stopwatch();

            var producer = new Thread(() => 
            {
                Debug.WriteLine("Production : started.");

                while (isProducing)
                {
                    var item = rng.Next(0, 100);

                    lock (mtxData)
                        data.Enqueue(new Tuple<long, int>(produced, item));

                    signal();
                    Debug.WriteLine($"{watch.Elapsed.Seconds,3:d}.{watch.Elapsed.Milliseconds:d3} Producer: {produced,6:d} [{item,3:d}]");

                    ++produced;
                }

                Debug.WriteLine("Production : finished.");
            }){Name = "Producer"};

            var consumer = new Thread(() => 
            {
                Debug.WriteLine("Consumption: started.");

                while (   (isConsuming)
                       || (data.Count > 0))
                {
                    while (data.Count > 0)
                    {
                        Tuple<long, int> record;

                        lock (mtxData)
                            record = data.Dequeue();

                        Debug.WriteLine($"{watch.Elapsed.Seconds,3:d}.{watch.Elapsed.Milliseconds:d3} Consumer: {record.Item1,6:d} [{record.Item2,3:d}]");
                        ++consumed;
                    }

                    wait();
                }

                Debug.WriteLine("Consumption: finished.");
            }){Name = "Consumer"};

            var timer = new Timer(5000){AutoReset = false};
            timer.Elapsed += (s, e) => {isProducing = false;};

            Console.WriteLine($"Evaluating \"{methodName}\"...");
            watch.Start();
            timer.Enabled = true;
            isConsuming = true;
            isProducing = true;
            consumer.Start();
            producer.Start();            
            producer.Join();
            isConsuming = false;
            consumer.Join();
            watch.Stop();

            Console.WriteLine($"Produced items: {produced:### ### ##0}{((produced != consumed) ? $", Consumed items: {consumed:### ### ##0}" : "")}");
            Console.WriteLine();

            return produced;
        }

        public static void Evaluate()
        {
            const string strMonitorLock = "Monitor locking";
            const string strWaitHandle  = "AutoResetEvent";
            const int    waitTimeout    = 500;

            var semMonitorLock = new object();
            var semWaitHandle  = new AutoResetEvent(false);

            var cntMonitorLock = Evaluate
            (
                strMonitorLock,
                () => {lock (semMonitorLock) Monitor.Pulse(semMonitorLock);},
                () => {lock (semMonitorLock) Monitor.Wait (semMonitorLock, waitTimeout);}
            );

            var cntWaitHandle = Evaluate
            (
                strWaitHandle,
                () => semWaitHandle.Set(),
                () => semWaitHandle.WaitOne(waitTimeout)
            );

            Console.WriteLine($"{strMonitorLock} / {strWaitHandle} = {((double)cntMonitorLock / cntWaitHandle):0.000}");
            Console.WriteLine();
        }
    }

    class Program
    {
        static Program()
        {
            Debug.Listeners.Add(new TextWriterTraceListener(Console.Out));
        }

        static void Main(string[] args)
        {
            Measurement.Evaluate();
        }
    }
}

重复执行的控制台输出:

    
    Evaluating "Monitor locking"...
    Produced items: 15 710 306

    Evaluating "AutoResetEvent"...
    Produced items: 5 998 742

    Monitor locking / AutoResetEvent = 2,619

    Evaluating "Monitor locking"...
    Produced items: 11 697 953

    Evaluating "AutoResetEvent"...
    Produced items: 7 119 778

    Monitor locking / AutoResetEvent = 1,643

    Evaluating "Monitor locking"...
    Produced items: 11 662 575

    Evaluating "AutoResetEvent"...
    Produced items: 6 437 772

    Monitor locking / AutoResetEvent = 1,812

    Evaluating "Monitor locking"...
    Produced items: 12 981 254

    Evaluating "AutoResetEvent"...
    Produced items: 5 934 954

    Monitor locking / AutoResetEvent = 2,187

    Evaluating "Monitor locking"...
    Produced items: 14 661 293

    Evaluating "AutoResetEvent"...
    Produced items: 6 370 518

    Monitor locking / AutoResetEvent = 2,301

    Evaluating "Monitor locking"...
    Produced items: 15 050 786

    Evaluating "AutoResetEvent"...
    Produced items: 5 912 671

    Monitor locking / AutoResetEvent = 2,546