调用UI-Element时线程运行缓慢

时间:2012-04-18 14:05:56

标签: c# wpf multithreading user-interface dispatcher

我正在编写一个基准测试工具,它从一个线程中的本地服务器读取一堆变量。

            int countReads = 1000;

            Int64 count = 0;

            for (int i = 0; i < countReads; i++)
            {
                Thread.CurrentThread.Priority = ThreadPriority.Highest;
                DateTime start = DateTime.Now;

                session.Read(null, 0, TimestampsToReturn.Neither, idCollection, out ReadResults, out diagnosticInfos);

                DateTime stop = DateTime.Now;
                Thread.CurrentThread.Priority = ThreadPriority.Normal;

                TimeSpan delay = (stop - start);

                double s = delay.TotalMilliseconds;
                count += (Int64)s;

                Dispatcher.Invoke(DispatcherPriority.Render, new Action(() =>
                {
                    progressBar1.Value = i;
                }));
            }

            double avg = (double)count / countReads;

            Dispatcher.Invoke(DispatcherPriority.Input, new Action(() =>
            {
                listBox1.Items.Add(avg);
            }));

我正在计算进行阅读并在结束时获得平均时间跨度所花费的时间。

            DateTime start = DateTime.Now;

            session.Read(null, 0, TimestampsToReturn.Neither, idCollection, out ReadResults, out diagnosticInfos);

            DateTime stop = DateTime.Now

如果我在不更新进度条的情况下运行代码,则平均花费大约5毫秒。 但如果我用

运行它
            Dispatcher.Invoke(DispatcherPriority.Render, new Action(() =>
            {
                progressBar1.Value = i;
            }));

平均需要10毫秒。

我的问题是,为什么使用进度条时的时间跨度更高? 我只是计算阅读的时间跨度。不包括进度条更新。

有没有办法撤离ui画,这样才不会影响我的阅读时间?

感谢您的帮助。

祝你好运

3 个答案:

答案 0 :(得分:8)

停止使用Invoke将进度信息传输到UI线程。将进度信息发布到共享数据结构或变量,并在合理的时间间隔内使用计时器对其进行UI线程轮询。我知道似乎我们都被洗脑了以为Invoke是进行工人到UI线程交互的全部方法,但对于简单的进度信息,它可能(通常是)最糟糕的方法。

在UI线程上使用计时器的轮询方法具有以下优点。

  • 它打破了Invoke对UI和工作线程施加的紧密耦合。
  • UI线程决定何时以及多久更新一次进度信息,而不是相反。当你停下来思考它时,无论如何都应该如此。
  • 您可以在UI和工作线程上获得更多吞吐量。

我知道这并没有直接回答你的问题,为什么session.Read似乎运行得更慢。尝试更改策略,以便将推送模型(通过Invoke)更新进度信息到拉模型(通过计时器)。看看是否有所作为。即使它没有,我仍然会坚持拉模型,原因如上所示。

答案 1 :(得分:2)

以下是MSDN对Dispatcher.Invoke

所说的内容
  

在与Dispatcher关联的线程上执行指定的委托同步

因此,基本上,Dispatcher.Invoke会阻塞,直到调度程序线程处理请求为止。

请尝试Dispatcher.BeginInvoke

答案 2 :(得分:0)

如果当前正在执行的线程与您正在使用的Dispatcher相关联 - Invoke()将阻止此线程,因此在这种情况下尝试使用Dispatcher.BeginInvoke()它将异步执行此任务。

MSDN, Dispatcher.Invoke Method

  

Invoke是一个同步操作;因此,控制权不会返回   调用对象直到回调返回之后。

顺便说一句,感兴趣的是DispatcherPriority.Send