Thread runs slow when Invoke UI-Element - c#

i am programming a benchmark tool, that reads a bunch of variables from a local server in a thread.
int countReads = 1000;
Int64 count = 0;
for (int i = 0; i < countReads; i++)
{
Thread.CurrentThread.Priority = ThreadPriority.Highest;
DateTime start = DateTime.Now;
session.Read(null, 0, TimestampsToReturn.Neither, idCollection, out ReadResults, out diagnosticInfos);
DateTime stop = DateTime.Now;
Thread.CurrentThread.Priority = ThreadPriority.Normal;
TimeSpan delay = (stop - start);
double s = delay.TotalMilliseconds;
count += (Int64)s;
Dispatcher.Invoke(DispatcherPriority.Render, new Action(() =>
{
progressBar1.Value = i;
}));
}
double avg = (double)count / countReads;
Dispatcher.Invoke(DispatcherPriority.Input, new Action(() =>
{
listBox1.Items.Add(avg);
}));
I am calculating the timespan it took to proceed the read and getting the average timespan at the end.
DateTime start = DateTime.Now;
session.Read(null, 0, TimestampsToReturn.Neither, idCollection, out ReadResults, out diagnosticInfos);
DateTime stop = DateTime.Now
if i run the code without updating the progressbar it took about 5ms average.
but if i run it with
Dispatcher.Invoke(DispatcherPriority.Render, new Action(() =>
{
progressBar1.Value = i;
}));
it takes about 10 ms average.
My question is, why is the timespan higher when using the progressbar?
i am just calculating the timespan for the read. Not including the progressbar update.
Is there any way to evacuate the ui-painting so that it doesn´t effect my read-timespan?
Thanks for your help.
Best regards

Stop using Invoke to transfer progress information to the UI thread. Publish the progress information to a shared data structure or variable and have the UI thread poll for it using a timer on a reasonable interval. I know it seems like we have all been brainwashed into thinking Invoke is the be-all method for doing worker-to-UI thread interactions, but for simple progress information it can be (and often is) the worst method.
A polling method using a timer on the UI thread offers the following benefits.
It breaks the tight coupling that Invoke imposes on both the UI and worker threads.
The UI thread gets to dictate when and how often it should update the progress information instead of the other way around. When you stop and think about it this is how it should be anyway.
You get more throughput on both the UI and worker threads.
I know this does not directly answer your question as to why session.Read appears to run slower. Try changing your strategy for updating progress information from a push model (via Invoke) to a pull model (via a timer). See if that makes a difference. Even if it does not I would still stick with the pull model for the reasons listed above.

Here is what MSDN says about Dispatcher.Invoke
Executes the specified delegate synchronously on the thread the Dispatcher is associated with.
So, basically, Dispatcher.Invoke blocks until the dispatcher thread as handled the request.
Try Dispatcher.BeginInvoke instead.

If current executing thread is associated with Dispatcher you are using - Invoke() will block this thread so in this case try out using Dispatcher.BeginInvoke() it will do the job asynchronously.
MSDN, Dispatcher.Invoke Method:
Invoke is a synchronous operation; therefore, control will not return
to the calling object until after the callback returns.
BTW, just of interest try out DispatcherPriority.Send

I came 9 years late to the party, but I think this is an even easier solution: Just wait until the progress bar value reaches a certain threshold before updating it. In my example, I refresh the toolbar every fifth of the maximum value.
private static int progressBarMaxValue = -1;
private static int progressBarChunkSize = -1;
public static void progressBarSetNotRealTimeValue(ProgressBar progressBar, int argNewValue)
{
if (progressBarMaxValue != -1)
{
if (argNewValue < progressBarChunkSize)
{
//Threshold not reached yet, discard the new value.
return;
}
else
{
//Allow the update, and set the next threshold higher.
progressBarChunkSize += progressBarChunkSize;
}
}
if (Thread.CurrentThread.IsBackground)
{
progressBar.BeginInvoke(new Action(() =>
{
if (progressBarMaxValue == -1)
{
progressBarMaxValue = progressBar.Maximum;
progressBarChunkSize = progressBar.Maximum / 5;
}
progressBar.Value = argNewValue;
}));
}
else
{
progressBar.Value = argNewValue;
}
}

Related

C# WinForms Trying to Update UI with Timer but without slowing the performance down

so currently I've got an application that has 2 processes. One process is pining, while pinging the process is writing down the results into an array.
Another process is for updating the UI every second with a timer. Whats being update is an mschart to be more exact.
That's how I have set up the timer:
readonly System.Windows.Forms.Timer myTimer = new System.Windows.Forms.Timer();
myTimer.Interval = 1000;
myTimer.Tick += WriteFunction;
Now this is the method that I'm calling every second for refreshing the UI / actually Graph:
private void WriteFunction(object objectInfo, EventArgs e)
{
foreach (NetPinger.source.AddGraph b in graphList)
{
b.fileRead();
}
}
The method, for updating the chart is inside another class, and looks like this:
public void fileRead()
{
double unixTimestamp = (Int32)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds;
chart_holder.Series[0].Points.Clear();
for (double i = unixTimestamp; unixTimestamp - graphSizing < i; i--)
{
bool exists;
try
{
exists = Array.Exists(file, element => element.XValue == i);
exists = true;
}
catch
{
exists = false;
}
try
{
if (exists == false)
{
DataPoint point = new DataPoint(i, 0);
chart_holder.Series[0].Points.Add(point);
}
else
{
DataPoint point = Array.Find(file, element => element.XValue == i);
chart_holder.Series[0].Points.Add(point);
}
}
catch(Exception ex)
{
MessageBox.Show(Convert.ToString(ex));
}
}
}
Now what I noticed was that if the graphSizing (number that I'm looping through) is kept low, the performance is kinda fine and everything is sync (multiple graphs from UI are updated at same time etc.) like it should be. But as soon as i rise it let's say to like 50 or even 250 (what the goal should be) the UI and Graph updating are being very very slow. It's only updating like every 3s and the UI is in general very laggy and slow.
Does anyone has any advice how I can maintain good performance or where I messed up that the UI is so slow? For further questions or more details feel free to ask.
Thanks a lot for your time and helping.
Greetings C.User
Your code always runs in the UI thread, since System.Windows.Forms.Timer calls the delegate on the UI thread. Even if that where not the case (and you used System.Timer instead), you delegate everything back to the UI with your Invoke call. You need to make sure you prepare the data on another thread first and do as little as possible in the UI thread itself.

WPF strange behavior with thread adn invoke to update progress bar

I have a method that reads from database and return result items one by one using yield return. I call it in foreach loop and at each iteration it invokes to STA thread for update ProgressBar. In this case I get about 6 seconds for all for some params. But if I remove Invoke, then I get 28 seconds for the same params. I test this behavior in separate application and can say that with Invoke each iterations to main thread processing in 10 times slower. However, Invoke is allmost at 6 times faster (not slower!) in my application than in other completed examples.
Any suggestions?
In general it looks like this:
Thread thread = new Thread(() =>
{
int itemNumber = 0;
foreach (object item in SelectItems())
{
itemNumber++;
// doing some staff ...
Application.Current.Dispatcher.Invoke(
new Action(() =>
{
ProgressBar1.Value = itemNumber * 100 / count;
}),
null);
}
});
thread.IsBackground = true;
thread.Start();
Update
I think I need to say that is big application and there is about half hundred background threads. And I don't think they all can work at same time.

Need Observable timer to pass messages to UI thread

This code, called from the UI thread:
Jobs.Current.ShowProgress(_ =>
{
if (Jobs.Current.Duration == 0 && this.progressBarMarkJob.Value >= this.progressBarMarkJob.Maximum - this.progressBarMarkJob.Step / 2)
{
this.progressBarMarkJob.Step /= 2;
}
this.progressBarMarkJob.PerformStep();
}, () =>
{
stopwatch.Stop();
var elapsed = string.Format(stopwatch.Elapsed.TotalHours >= 1 ? #"{0:hh\:mm\:SS}" : #"{0:mm\:SS}", stopwatch.Elapsed);
this.labelMarkTime.Text = string.Format("Elapsed{0:8}", elapsed);
this.labelMarkTime.Visible = true;
Jobs.Current.Duration = (uint)stopwatch.Elapsed.TotalSeconds;
this.progressBarMarkJob.Value = this.progressBarMarkJob.Maximum;
});
where ShowProgress does:
public void ShowProgress(Action<long> notify, Action terminate)
{
this.Progress = Observable.Timer(ProgressInterval, ProgressInterval).Finally(terminate).Subscribe(notify);
}
blocks the UI thread completely, making it unresponsive.
If I insert .SubscribeOn(Scheduler.CurrentThread) before the Subscribe() call, it no longer blocks the UI thread. But then I get cross-thread exceptions, because the messages are not passed to the UI on the correct thread.
Is there a way to make that work so that I can get updates from the timer - leaving the UI responsive - that post back to the UI thread?
You need to add a call to ObserveOn(). If you use nuget package Rx-Xaml you can leverage ObserveOnDispatcher():
this.Progress = Observable.Interval(ProgressInterval)
.ObserveOnDispatcher()
.Finally(terminate)
.Subscribe(notify);
See my answer here to understand the difference between ObserveOn and SubscribeOn. Also, you don't supply the code for PerformStep() - I hope that it is fast and/or non-blocking.
I also replaced Timer with Interval as it saves you an argument.
Finally, presumably you are planning to dispose the subscription handle (this.Progress) when the job completes?

Dedicated C# class to update progressbar

I would like to make a dedicated class to update the progress bar in my apps (in this case a WPF progressbar). I did something like this :
public class ProgressBarUpdate : IDisposable
{
private readonly double _delta;
private int _current;
private int _total;
private readonly ProgressBar _pb;
public ProgressBarUpdate(ProgressBar pb, int total)
{
_pb = pb;
_total = total;
// the pb.Maximum is a double so it doesn`t get truncated
_delta = _pb.Maximum / total;
_current = 0;
_pb.Visibility = Visibility.Visible;
}
public void Dispose()
{
_pb.Visibility = Visibility.Collapsed;
_current = 0;
}
public void UpdateProgress()
{
_pb.Value =(int)_delta * (++_current);
}
That i use like this (in the UI thread) :
using (var pu = new ProgressBarUpdate(pb, totalCount)
{
for (x=0; x<totalCount; x++)
{
// operations here
pu.UpdateProgress()
}
}
But the UI, probably blocked, is not updating correctly. What is the best way to display all the progress?
Winforms/WPF program is an Eventing system. There is a single thread which continuously processes events from an event queue. That is its main job and ideally that is the only thing which it should do. Any sort of UI activity generates events in the event queue - like you move your mouse over the window or click something or some other window overlaps your window and then again when it goes away from the overlapped position. All these events are processed by the UI thread and that keeps the UI updated all the time.
Further, Winforms/WPF make it necessary to access and/or update controls and their properties in a thread safe manner by allowing it only on the UI thread.
If you block this UI thread or do some other CPU bound calculation on it, then your UI responsiveness and updated behavior will suffer. Worst case UI will freeze.
Hence the correct answer for you is to do your calculation loop on another worker thread and only update the progress bar UI by marshaling the call to UI thread using the Dispatcher.
However, to answer your question and satisfy your inquisition, here is something that is possible - but it is bad practice and your should never do the following...:
To make it simple, when you update the Value property of the progress bar, it invalidates the progress bar UI - so, UI must update. Hence lets say an event is generated in the event queue which will cause some code to run which will update the UI. However, you are running in a loop over the UI thread - so, the thread has no chance to process this event unless your loop is over. Hence you don't see any UI update. The trick is to make the UI thread process that event before you make the next update on the Value of progress bar. You can do this by forcefully invoking a lower priority item into the event queue - so that normal and higher priority items are processed before going to the next iteration.
using (var pu = new ProgressBarUpdate(pb, totalCount))
{
for (int x = 0; x < totalCount ; x++)
{
// operations here
pu.UpdateProgress();
Dispatcher.Invoke(DispatcherPriority.Background, new Action(()=>{}));
}
}
If you're doing your work, and calling UpdateProgress, on the UI thread then it won't update until you finish the work and the UI thread can do other work (like refresh the UI). So this will never work.
If you're doing your work on a background thread, then you need to use a Dispatcher to marshal the setting the value to the UI thread.
Here's an example from http://tech.pro/tutorial/800/working-with-the-wpf-dispatcher
if (!myCheckBox.Dispatcher.CheckAccess())
{
myCheckBox.Dispatcher.Invoke(
System.Windows.Threading.DispatcherPriority.Normal,
new Action(
delegate()
{
myCheckBox.IsChecked = true;
}
));
}
else
{
myCheckBox.IsChecked = true;
}
Try this:
public ProgressBarUpdate(ProgressBar pb, int total)
{
_pb = pb;
_total = total;
_delta = _pb.MaxValue/((double)total); /make sure you do not truncate delta
_current = 0;
_pb.Visibility = Visibility.Visible;
}
public void Dispose()
{
_pb.Visibility = Visibility.Collapsed;
_current = 0;
}
public void UpdateProgress()
{
_pb.Value = (int)( _delta * (++_current)); //update after the increment
}
I suggest also using float instead of double.
You've been saying you want to avoid using threads, I assume because you don't want unnecessary complication, but it's really not a big deal. It's a very simple matter to make an operation multi-threaded. Even for very short and simple tasks, this is the most straightforward way to achieve what you want. Using TPL, it would look something like this:
using System.Threading.Tasks;
...
Task.Factory.StartNew(() => {
for (...) {
// operation...
progressBar.Dispatcher.BeginInvoke(() => progressBar.Value = ...);
}
});

Show progress only if a background operation is long

I'm developing a C# operation and I would like to show a modal progress dialog, but only when an operation will be long (for example, more than 3 seconds). I execute my operations in a background thread.
The problem is that I don't know in advance whether the operation will be long or short.
Some software as IntelliJ has a timer aproach. If the operation takes more than x time, then show a dialog then.
What do you think that is a good pattern to implement this?
Wait the UI thread with a timer, and show dialog there?
Must I DoEvents() when I show the dialog?
Here's what I'd do:
1) Use a BackgroundWorker.
2) In before you call the method RunWorkerAsync, store the current time in a variable.
3) In the DoWork event, you'll need to call ReportProgress. In the ProgressChanged event, check to see if the time has elapsed greater than three seconds. If so, show dialog.
Here is a MSDN example for the BackgroundWorker: http://msdn.microsoft.com/en-us/library/cc221403(v=vs.95).aspx
Note: In general, I agree with Ramhound's comment. Just always display the progress. But if you're not using BackgroundWorker, I would start using it. It'll make your life easier.
I will go with the first choice here with some modifications:
First run the possible long running operation in different thread.
Then run a different thread to check the first one status by a wait handle with timeout to wait it for finish. if the time out triggers there show the progress bar.
Something like:
private ManualResetEvent _finishLoadingNotifier = new ManualResetEvent(false);
private const int ShowProgressTimeOut = 1000 * 3;//3 seconds
private void YourLongOperation()
{
....
_finishLoadingNotifier.Set();//after finish your work
}
private void StartProgressIfNeededThread()
{
int result = WaitHandle.WaitAny(new WaitHandle[] { _finishLoadingNotifier }, ShowProgressTimeOut);
if (result > 1)
{
//show the progress bar.
}
}
Assuming you have a DoPossiblyLongOperation(), ShowProgressDialog() and HideProgressDialog() methods, you could use the TPL to do the heavy lifting for you:
var longOperation = new Task(DoPossiblyLongOperation).ContinueWith(() => myProgressDialog.Invoke(new Action(HideProgressDialog)));
if (Task.WaitAny(longOperation, new Task(() => Thread.Sleep(3000))) == 1)
ShowProgressDialog();
I would keep the progress dialog separate from the background activity, to separate my UI logic from the rest of the application. So the sequence would be (This is essentially the same as what IntelliJ does):
UI starts the background operation (in a BackgroundWorker) and set up a timer for X seconds
When the timer expires UI shows the progress dialog (if the background task is still running)
When the background task completes the timer is cancelled and the dialog (if any) is closed
Using a timer instead of a separate thread is more resource-efficient.
Recommended non-blocking solution and no new Threads:
try
{
var t = DoLongProcessAsync();
if (await Task.WhenAny(t, Task.Delay(1000)) != t) ShowProgress();
await t;
}
finally
{
HideProgress();
}
I got the idea from Jalal Said answer. I required the need to timeout or cancel the progress display. Instead of passing an additional parameter (cancellation token handle) to the WaitAny I changed the design to depend on Task.Delay()
private const int ShowProgressTimeOut = 750;//750 ms seconds
public static void Report(CancellationTokenSource cts)
{
Task.Run(async () =>
{
await Task.Delay(ShowProgressTimeOut);
if (!cts.IsCancellationRequested)
{
// Report progress
}
});
}
Use it like so;
private async Task YourLongOperation()
{
CancellationTokenSource cts = new CancellationTokenSource();
try
{
// Long running task on background thread
await Task.Run(() => {
Report(cts);
// Do work
cts.Cancel();
});
}
catch (Exception ex) { }
finally {cts.Cancel();}
}

Categories

Resources