讓我設置這個問題與一些背景信息,我們有一個長期運行的過程,將在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線程會變得緊張,試圖跟上並且永遠無法趕上。並停止繪畫並響應輸入。 –