什么是更快更有效的 - begininvoke或synchronisecontext.post?

时间:2011-11-22 21:45:43

标签: c# wpf .net-4.0 multithreading

有没有人试图找出 - 什么是更快,什么更有效(创建的对象更少,因此涉及的GC更少) - control.BeginInvoke或SynchroniseContext.Post?

WPF,C#,.NET 4

我很欣赏以实际支持而非“我认为”或“我在某处听到”的回应。

干杯

P.S。我将向一些控件发布一些消息,我希望它能够最快速有效(几百次更新/秒)。我知道.NET可以处理这个问题(我之前做过),但现在我想让它尽快 ......

2 个答案:

答案 0 :(得分:4)

首先,WPF中没有Control.BeginInvoke(这是你想到的winforms)。其次,SynchronizationContext是对当前平台提供的任何同步机制的抽象。在WPF的情况下,它是Dispatcher的抽象。从理论上讲,你为使用抽象而不是直接使用Dispatcher付出了很小的代价。但抽象是有充分理由的 - 有时您需要编写独立于平台的线程同步代码。如果不这样做,请务必直接使用Dispatcher

答案 1 :(得分:2)

我的i7桌面上的BeginInvoke比SynchronizationContext.Post快42.8%。

结果是:

Post      Send      Diff ms   Ratio
1280866   925416    35.00     -38.4%
1192232   916251    27.00     -30.1%
1338990   876215    46.00     -52.8%
1394783   863241    53.00     -61.6%
1332485   1046789   28.00     -27.3%
1335241   895784    43.00     -49.1%
1267470   1064894   20.00     -19.0%
1308461   884136    42.00     -48.0%
1321243   850704    47.00     -55.3%
1313230   896469    41.00     -46.5%

代码:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.RealTime;
    }

    Thread th;
    DispatcherSynchronizationContext ctx;
    protected override void OnContentRendered(EventArgs e)
    {
        base.OnContentRendered(e);

        Thread.CurrentThread.Priority = ThreadPriority.Highest;

        ctx = new DispatcherSynchronizationContext(this.Dispatcher);
        th = new Thread(Start);
        th.Start();
    }

    int MACRO = 10;
    int TESTS = 10;
    int LOOPS = 50000;
    void Start()
    {
        Thread.CurrentThread.Priority = ThreadPriority.AboveNormal;

        // flush just in case
        for (int i = 0; i < 100; i++)
        {
            ctx.Post(Callback, 9999999);
            this.Dispatcher.BeginInvoke(
                new Action<object>((object state) => { txt2.Text = state.ToString(); }), 
                    DispatcherPriority.Send, 9999999);                
        }

        Thread.Sleep(1000);

        // results
        List<Tuple<long, long>> results = new List<Tuple<long, long>>();

        // actual test
        for (int x = 0; x < MACRO; x++)
        {
            Stopwatch sw = new Stopwatch();

            // sync context post
            long tick1, tick2;
            for (int i = 0; i < TESTS; i++)
            {
                sw.Start();
                for (int j = i; j < LOOPS + i; j++)
                {
                    ctx.Post(Callback, j);
                }
                sw.Stop();

                Thread.Sleep(1500);
            }

            tick1 = sw.ElapsedTicks;

            // begin invoke
            sw.Reset();
            for (int i = 0; i < TESTS; i++)
            {
                sw.Start();
                for (int j = i; j < LOOPS + i; j++)
                {
                    this.Dispatcher.BeginInvoke(
                        new Action<object>((object state) => { txt2.Text = state.ToString(); }), 
                            DispatcherPriority.Normal, j);
                }
                sw.Stop();

                Thread.Sleep(1500);
            }

            tick2 = sw.ElapsedTicks;

            // store results
            results.Add(new Tuple<long, long>(tick1, tick2));

            // display to make it less boring
            this.Dispatcher.BeginInvoke(new Action(() => { txt3.Text += string.Format("{0} {1}. ", tick1, tick2); }));
            Thread.Sleep(100);                
        }

        StringBuilder sb = new StringBuilder();
        foreach (var res in results)
            sb.AppendLine(string.Format("{0}\t{1}\t{2:0.00}\t{3:0.0%}", 
                res.Item1, res.Item2, (res.Item1 - res.Item2) / 10000, res.Item2 != 0 ? 1.0 - res.Item1 / (double)res.Item2 : 0.0));

        this.Dispatcher.BeginInvoke(
            new Action(() => { txb1.Text = sb.ToString(); }));                

    }

    void Callback(object state)
    {
        txt1.Text = state.ToString();
    }
}