[英]UI is being blocked by Performance counters
所以我有一個按鈕、一個面板和一個用戶控件,單擊按鈕時,用戶控件被調用並顯示在面板上,問題是由於性能計數器,用戶控件需要大約 4-5 秒才能顯示。
usercontrol 包含一個計時器,計時器只是更新兩個標簽(以顯示 cpu 和 ram 使用情況)
private void UpdateUI_Tick(object sender, EventArgs e)
{
Task.Run(() => {
LabelCPU.Text = $"CPU : {(int)PerformanceCounterCPU.NextValue()}%";
LabelMemory.Text = $"Memory : {(int)PerformanceCounterMemory.NextValue()}%";
});
}
我什么都試過了,但它一直在凍結。
用戶控件包含以下代碼:
private static UserControlLogs _instance;
public static UserControlLogs Instance
{
get
{
if (_instance == null || _instance.IsDisposed)
_instance = new UserControlLogs();
return _instance;
}
}
調用用戶控件的按鈕代碼:
if (!PanelMain.Controls.Contains(UserControls.UserControlLogs.Instance))
{
PanelMain.Controls.Add(UserControls.UserControlLogs.Instance);
uc.Dock = DockStyle.Fill;
uc.BringToFront();
}
else
{
uc.BringToFront();
}
根據我們的談話,即使在應用了各種策略之后,您仍然會遇到系統凍結。 重新啟用此答案的目的是顯示到目前為止已嘗試過的所有內容。 這樣,如果其他人想嘗試一下,他們將能夠開辟新天地。
UserControl
的OnVisibleChanged
以進行初始化。 啟動一個任務以在第一次出現 Visible 時創建 PerformanceCounters(在它發生時旋轉 WaitCursor),然后啟動計時器。public partial class UserControlLogs : UserControl
{
protected override void OnVisibleChanged(EventArgs e)
{
base.OnVisibleChanged(e);
if(Visible)
{
if(PerformanceCounterCPU == null)
{
Task.Run(()=>
{
Parent?.Invoke((MethodInvoker)delegate { Parent.UseWaitCursor = true; });
Debug.WriteLine($"{UserControlLogs.Stopwatch.Elapsed}: Initializing Performance Counters");
UserControlLogs.Stopwatch.Restart();
PerformanceCounterCPU = new PerformanceCounter("Processor", "% Processor Time", "_Total");
PerformanceCounterCommittedMemory = new PerformanceCounter("Memory", "% Committed Bytes In Use");
PerformanceCounterAvailableMemory = new PerformanceCounter("Memory", "Available MBytes");
Debug.WriteLine($"{UserControlLogs.Stopwatch.Elapsed}: Initialization complete");
UserControlLogs.Stopwatch.Restart();
Parent?.BeginInvoke((MethodInvoker)delegate
{
Parent.UseWaitCursor = false;
timerUpdateUI.Enabled = true;
});
});
}
}
}
}
添加信號量以阻止重入。 如果任務沒有機會完成,這將避免啟動新任務並讓它們堆積起來。
將數據的獲取與 UI 的更新分開。 PerformanceCounters 可以在后台線程上讀取。 然后只需獲取結果並將其編組回 UI 線程以顯示。
添加Stopwatch
以診斷導致瓶頸的確切行。 Output Elapsed 間隔到 Debug window 來監控。
public partial class UserControlLogs : UserControl
{
public static Stopwatch Stopwatch { get; } = new Stopwatch();
public UserControlLogs()
{
InitializeComponent();
timerUpdateUI.Enabled = false;
}
private PerformanceCounter PerformanceCounterCPU = null;
private PerformanceCounter PerformanceCounterCommittedMemory = null;
private PerformanceCounter PerformanceCounterAvailableMemory = null;
SemaphoreSlim _noReentrancy = new SemaphoreSlim(1, 1);
// Handler is now async
private async void timerUpdateUI_Tick(object sender, EventArgs e)
{
int cpu = 0, committed = 0, available = 0;
// Skip if task is still busy getting the Performance Counter from last time.
if (_noReentrancy.Wait(0))
{
var cts = new CancellationTokenSource();
var wdt = startWatchdog(TimeSpan.FromSeconds(2));
try
{
_ = Task.Run(() => getPerformance());
await wdt;
BeginInvoke((MethodInvoker)delegate { updateUI(); });
}
catch (TimeoutException ex)
{
Debug.WriteLine($"{DateTime.Now} {ex.Message}");
}
finally
{
_noReentrancy.Release();
}
void getPerformance()
{
Debug.WriteLine($"{UserControlLogs.Stopwatch.Elapsed}: Getting performance data");
UserControlLogs.Stopwatch.Restart();
cpu = (int)PerformanceCounterCPU.NextValue();
committed = (int)PerformanceCounterCommittedMemory.NextValue();
available = (int)PerformanceCounterAvailableMemory.NextValue();
cts.Cancel(); // Cancel the WDT
Debug.WriteLine($"{UserControlLogs.Stopwatch.Elapsed}: Performance data received");
UserControlLogs.Stopwatch.Restart();
}
void updateUI()
{
Debug.WriteLine($"{UserControlLogs.Stopwatch.Elapsed}: UI Updating");
UserControlLogs.Stopwatch.Restart();
labelCPU.Text = $"{cpu}%";
labelMemoryCommitted.Text = $"{committed}%";
labelMemoryAvailable.Text = $"{available}%";
_colorToggle = !_colorToggle;
if(_colorToggle) BackColor = Color.LightCyan;
else BackColor = Color.LightBlue;
Debug.WriteLine($"{UserControlLogs.Stopwatch.Elapsed}: UI Updated");
UserControlLogs.Stopwatch.Restart();
}
async Task startWatchdog(TimeSpan timeout)
{
try
{
Debug.WriteLine($"{UserControlLogs.Stopwatch.Elapsed}: Watchdog Started");
UserControlLogs.Stopwatch.Restart();
await Task.Delay(timeout, cts.Token);
Debug.WriteLine($"{UserControlLogs.Stopwatch.Elapsed}: Watchdog Timed Out");
UserControlLogs.Stopwatch.Restart();
throw new TimeoutException();
}
catch (TaskCanceledException)
{
Debug.WriteLine($"{UserControlLogs.Stopwatch.Elapsed}: Watchdog Cancelled");
UserControlLogs.Stopwatch.Restart();
}
}
}
}
}
BeginInvoke
顯示 UserControl。public partial class MainForm : Form
{
public MainForm()
{
UserControlLogs.Stopwatch.Start();
Debug.WriteLine($"{UserControlLogs.Stopwatch.Elapsed}: MainForm CTor:");
InitializeComponent();
}
private void buttonShowUC_Click(object sender, EventArgs e)
{
BeginInvoke((MethodInvoker)delegate
{
Debug.WriteLine($"{UserControlLogs.Stopwatch.Elapsed}: ShowUC Click:");
UserControlLogs.Stopwatch.Restart();
_instance.Show();
});
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.