[英]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.