I am new to TPL and I am trying to test a very simple application using parallelism.
I am using a WinForms, C#, VS2015
In my form, I have one progress bar, a timer and a gauge. I am using Infragistics 15.2 controls.
PerformanceCountertimer.Tick (I set a 500ms interval), I read the CPU usage from the PerformanceCounter and update the value of the Gauge control.My problem is that the first access to NextValue() of the CPU counter is really time expensive and freezes the UI.
I was expecting to have a full responsive UI but still it freezes. I am missing something for sure, but I cannot find out what.
I am pretty sure that The blocking action is the NextValue(): if I replace it with a random number generator, my UI is fully responsive.
Can you please help me?
public partial class Form1 : Form
{
PerformanceCounter _CPUCounter;
public Form1()
{
InitializeComponent();
}
private async void ultraButton1_Click(object sender, EventArgs e)
{
var progress = new Progress<int>(valuePBar => {ultraProgressBar1.Value = valuePBar; });
await Task.Run(() => UpdatePBar(progress));
}
private void Form1_Load(object sender, EventArgs e)
{
Task.Run(() =>
{
_CPUCounter = new PerformanceCounter();
_CPUCounter.CategoryName = "Processor";
_CPUCounter.CounterName = "% Processor Time";
_CPUCounter.InstanceName = "_Total";
BeginInvoke(new Action(() =>
{
timer1.Interval = 500;
timer1.Start();
}));
});
}
private async void timer1_Tick(object sender, EventArgs e)
{
float usage = await Task.Run(() => _CPUCounter.NextValue());
RadialGauge r_gauge = (RadialGauge)ultraGauge1.Gauges[0];
r_gauge.Scales[0].Markers[0].Value = usage;
}
public void UpdatePBar(IProgress<int> progress)
{
for (Int32 seconds = 1; seconds <= 10; seconds++)
{
Thread.Sleep(1000); //simulate Work, do something with the data received
if (seconds != 10 && progress != null)
{
progress.Report(seconds * 10);
}
}
}
}
You should:
Task.Run over Task.Factory.StartNew.async/await if you want to "return to the UI thread".IProgress<T> for progress updates.TaskSchedulers or SynchronizationContexts if absolutely necessary (and they're not necessary here).Control.BeginInvoke or Control.Invoke.In this case, your timer can just run NextValue on a thread pool thread using Task.Run, and then update the UI with the resulting value:
private async void OnTimerTickElapsed(Object sender, EventArgs e)
{
float usage = await Task.Run(() => _CPUCounter.NextValue());
RadialGauge r_gauge = (RadialGauge)this.ultraGauge.Gauges[0];
r_gauge.Scales[0].Markers[0].Value = usage;
}
For your progress bar, have your MyMethod take an IProgress<int>:
private void ButtonClick(Object sender, EventArgs e)
{
var progress = new Progress<int>(valuePBar => { this.progressBar.Value = valuePBar; });
MyMethod(progress);
}
MyMethod(IProgress<int> progress)
{
...
progress.Report(50);
...
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With