让我设置这个问题与一些背景信息,我们有一个长期运行的过程,将在Windows窗体中生成数据。所以,显然需要某种形式的多线程来保持表单的响应。但是,我们也有要求,表格每秒更新多次,同时仍然保持响应。Winforms更新与高性能
下面是使用后台工作线程创建一个简单的测试,例如:
void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
int reportValue = (int)e.UserState;
label1.Text = reportValue;
//We can put this.Refresh() here to force repaint which gives us high repaints but we lose
//all other responsiveness with the control
}
void bw_DoWork(object sender, DoWorkEventArgs e)
{
for (int x = 0; x < 100000; x++)
{
//We could put Thread.Sleep here but we won't get highest performance updates
bw.ReportProgress(0, x);
}
}
请参阅代码中的注释。另外,请不要质疑我为什么要这样做。这个问题很简单,我们如何在保持响应性的同时更新表单来实现最高保真度(大多数重绘)?强制重新绘制确实给了我们更新,但我们不处理Windows消息。
我也尝试放置DoEvents但产生堆栈溢出。我需要的是某种方式来说,“如果你最近没有处理任何Windows消息”。我可以看到,也许需要一个稍微不同的模式来实现这一点。
看来,我们需要处理的几个问题:
- 通过非UI线程更新表格。这个问题有很多解决方案,例如invoke,同步上下文,后台工作模式。
- 第二个问题是充斥着太多阻止消息处理的更新窗体,这是我的问题真正关注的问题。在大多数示例中,通过使用任意等待减慢请求或仅更新每个X%来简化处理。这些解决方案都不适用于真实世界的应用程序,也不符合响应标准的最大更新。
我的一些关于如何处理这个初始的想法:
- 队列中后台工作项目,然后派遣他们在UI线程。这将确保每个项目都被绘制,但会导致我们不想要的滞后。
- 也许使用TPL
- 也许在UI线程中使用一个定时器来指定刷新值。通过这种方式,我们可以以我们可以处理的最快速度获取数据。它将要求跨线程访问/共享数据。
更新,我已经更新了使用计时器来读取一个共享变量与背景工作者线程更新。现在由于某种原因,这种方法产生了良好的表单响应,并且允许后台工作人员以最快的速度更新大约1,000倍。但是,有趣的是,它只有1毫秒的准确度。
所以我们应该能够改变模式来读取当前时间并从bw线程调用更新而不需要计时器。
这是新模式:
//Timer setup
{
RefreshTimer.SynchronizingObject = this;
RefreshTimer.Elapsed += RefreshTimer_Elapsed;
RefreshTimer.AutoReset = true;
RefreshTimer.Start();
}
void bw_DoWork(object sender, DoWorkEventArgs e)
{
for (int x = 0; x < 1000000000; x++)
{
//bw.ReportProgress(0, x);
//mUiContext.Post(UpdateLabel, x);
SharedX = x;
}
}
void RefreshTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
label1.Text = SharedX.ToString();
}
更新在这里,我们有不需要计时器,并不会阻止该线程的新的解决方案!我们在计算和高保真度模式下实现更新。不幸的是,tickCount只有1 MS精度,但是我们可以对每个MS运行一批X更新,以便获得更快的1 MS定时。
void bw_DoWork(object sender, DoWorkEventArgs e)
{
long lastTickCount = Environment.TickCount;
for (int x = 0; x < 1000000000; x++)
{
if (Environment.TickCount - lastTickCount > 1)
{
bw.ReportProgress(0, x);
lastTickCount = Environment.TickCount;
}
}
}
你试图做的是非常毫无意义和自我挫败。你只是这样做才能保持人性化的乐趣。除了超出每秒25次更新的模糊之外,它无法感知任何东西。做得更快只是浪费CPU周期。而自我挫败,因为如果你做得太快(每秒约1000次),那么UI线程会变得紧张,试图跟上并且永远无法赶上。并停止绘画并响应输入。 –