Что быстрее и эффективнее - begininvoke или synchronisecontext.post? - PullRequest
3 голосов
/ 23 ноября 2011

Кто-нибудь пытался выяснить - что быстрее и что эффективнее (меньше объектов создано и, следовательно, меньше GC) - control.BeginInvoke или SynchroniseContext.Post?

WPF, C #, .NET4

Я бы оценил ответы с практической поддержкой, а не "Я думаю" или "Я где-то слышал" ..

Приветствия

PS Я собираюсьотправьте несколько сообщений нескольким элементам управления, и я хочу, чтобы это было максимально эффективно и быстро ( несколько сотен обновлений в секунду ).Я знаю, что .NET может справиться с этим (я делал это раньше), но теперь я хочу, чтобы он был как можно быстрее ...

Ответы [ 2 ]

4 голосов
/ 23 ноября 2011

Во-первых, в WPF нет Control.BeginInvoke (это формы win-win, о которых вы думаете). Во-вторых, SynchronizationContext - это абстракция любого механизма синхронизации, предоставляемого текущей платформой. В случае с WPF это абстракция над Dispatcher. Теоретически вы платите небольшую цену за использование абстракции, а не за прямое использование Dispatcher. Но абстракция существует по уважительной причине - иногда вам нужно написать код синхронизации потоков, который не зависит от платформы. Если вы этого не сделаете, во что бы то ни стало, используйте Dispatcher напрямую.

2 голосов
/ 24 ноября 2011

BeginInvoke на 42,8% быстрее, чем SynchronizationContext.Post на рабочем столе i7.

Результаты:

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();
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...