We are working on a windows application which caters to an engineering calculation which are essentially very long running. So we are basically trying to keep the calculation module separate and working in a separate worker thread and pass it an Action delegate in method signature which will be invoked to report the calculation progress in the UI. The delegate handler declared in the UI will be updating the UI. We found that while a huge loop is running in the calculation, the UI is not showing the periodic progress and only displaying the final result. If a Thread Sleep for 1 millisecond is introduced in the calculation loop, the UI is getting updated correctly. This is not expected behavior as we are executing the calculation using a separate Task and updating the UI using BeginInvoke calls.
I have created a simple application to demonstrate our approach and code so that it is easier to understand. It is obvious that we are missing something very simple but cannot quite pin it down. Will appreciate any insights.
Thanks for reading.
private void cmdStart_Click(object sender, EventArgs e)
{
txtResultDIsplay.Text = "";
var maxIterations = long.Parse(txtIterationNo.Text.Trim());
var ui = TaskScheduler.FromCurrentSynchronizationContext();
Task<double> calculationTask = Task.Factory.StartNew<double>(
() => SumRootN(maxIterations, UpdateProgress));
var handleResultTask = calculationTask.ContinueWith((t) => DisplayResult(t),
CancellationToken.None, TaskContinuationOptions.OnlyOnRanToCompletion, ui);
}
private void DisplayResult(Task<double> calculationTask)
{
txtResultDIsplay.Text = "Final Calculation Result : " + calculationTask.Result.ToString();
}
private void UpdateProgress(string msg)
{
this.BeginInvoke((MethodInvoker)delegate
{
txtResultDIsplay.Text = msg;
});
}
public double SumRootN(long maxIterations, Action<string> progressUpdateDelegate)
{
int root = 20;
double result = 0;
for (long i = 1; i < maxIterations; i++)
{
Thread.Sleep(1);
result += Math.Exp(Math.Log(i) / root);
progressUpdateDelegate(result.ToString("0.00000"));
}
return result;
}
It is possible you are flooding the UI thread with your progress updates. You need to find a way to prevent lots of updates occurring.
We can solve the problem using tasks!
Task progressTask = null;
private void UpdateProgress(string msg)
{
//only schedule work if the task if not running
if(progressTask == null || progressTask.IsCompleted) //updates will end if there is an exception!
{
//Create a task representing the update
progressTask = Task.Factory.FromAsync<object>(BeginInvoke(new Action(() => txtResultDIsplay.Text = msg)), this.EndInvoke)
.ContinueWith(() => System.Threading.Thread.Sleep(100)); //add a sleep on the end
}
}
Note that locking will not do here as you want to skip the update if there is already an update occurring.
Related
I have a viewmodel whose constructor leads to some asynchronous calls and I'm having trouble testing their result.
public ExamAcquireImageViewModel(ICore coreInstance, ExamManager examManager, Action cancelHandler) : base(examManager)
{
TemplateVm.OnSelectionChanged += StartAcquiringImages;
// BECAUSE OF PREVIOUS LINE, THIS CALLS StartAcquiringImages()
SelectedLocationInTemplate = SelectedLocationInTemplate ?? FindNextLowest();
}
private void StartAcquiringImages(LocationViewModel nextLocation = null)
{
new Thread(() =>
{
// expensive operation
_recon = _coreInstance.AcquireImageSet(Exam, SelectedLocationInTemplate.LocationModel);
int width = 1000;
int height = 1000;
// (less) expensive operation
AcquiredImage = _recon?.RenderImageAndGetCurrentFrame().ToWriteableBitmap(width, height);
SelectedLocationInTemplate = GetNextLocation();
}).Start();
}
The constructor assigns the OnSelectionChanged and then changes the selection, setting off the image acquisition process. I want to test that AcquireImages has been assigned to.
public void TestAcquisition()
{
ExamAcquireImageViewModel acqVm = new ExamAcquireImageViewModel(mockCore.Object, examManager, () => { });
Assert.IsNotNull(acqVm.AcquiredImage);
}
I have all my Moqs set up correctly. However because of the threaded/asynchronous operations, the test fails because the assertion runs before any AcquiredImage gets set (indeed, I imagine, before anything in the new Thread gets run).
I've tried ExamAcquireImageViewModel acqVm = await new ExamAcquireImageViewModel(mockCore.Object, examManager, () => { }); but that doesn't compile (no GetAwaiter etc).
How do I wait for this thread in my tests?
I'll also want to test that the SelectedLocationInTemplate "increments" automatically and each next image gets acquired (see last line in the Thread). I don't know where I'd intercept or "peek into" the whole process to see that happening.
For anyone who has a similar problem, I will answer my own question.
It's very very very simple. Thread.Sleep.
[TestMethod]
public void TestAcquisitionSucess()
{
ExamAcquireImageViewModel acqVm = GetAcqVm();
Thread.Sleep(30);
Assert.IsNotNull(acqVm.AcquiredImage);
}
Hello Stackoverflowers!
I have a strange situation here. I wrote a small C# tool, to measure the time it takes to send a request via usb and wait until the response arrives. The communication is no problem, nor are the devices.
I put a simple TextBox on the GUI together with a "Start" button.
Pressing "Start" starts a thread with a loop (loops defined in the TextBox) sending requests and receiving the answers. In the GUI thread you can see a progress bar showing the status.
When I pressed "Start" I measured around 15 ms per command and response (in average) which is quite a long time.
When I pressed "Start" and clicked inside the TextBox (only setting the cursor inside), the worker thread ran through with an average time of 1.6 ms per command and response.
This is reproducible in my case. I even put in a new, totally useless TextBox. When clicking inside, the thread speeds up, when I focus another element, like a slider, the thread slows down again.
Has anyone ever heard about something like that and can explain to me, why this happens? And even better, how I can avoid this behavior?
FYI:
- I tried both BackgroundWorker and Thread, same behavior.
- For taking the times, I'm using .NET's stopwatch.
- Executing the measurement method in the GUI thread changes nothing. EDIT: Tried again and everything's as it should be. But now I have the problem, that the GUI freezes, since I'm working in its thread.
- Removing the progress bar changes nothing.
Thanks a lot!
EDIT:
private void tbAmount_Copy_PreviewKeyUp(object sender, KeyEventArgs e)
{
if (e.Key == Key.Enter)
{
if (String.IsNullOrEmpty(tbDevAddrTime.Text))
return;
pbTimeMeasure.Value = 0;
worker = new BackgroundWorker();
worker.DoWork += new DoWorkEventHandler(StartTimeMeasureHandler);
worker.RunWorkerAsync();
}
}
private void StartTimeMeasure()
{
int address = 1;
int loops = 1;
DispatchIfNecessary(() =>
{
address = Convert.ToInt32(tbDevAddrTime.Text);
loops = Convert.ToInt32(tbAmount_Copy.Text);
pbTimeMeasure.Maximum = loops;
});
System.Diagnostics.Stopwatch stopwatchLong = new System.Diagnostics.Stopwatch();
System.Diagnostics.Stopwatch stopwatchShort = new System.Diagnostics.Stopwatch();
var cmd = String.Format(":{0:X3}4010200300000000\r", RequestAddress + address);
for (int i = 0; i < loops; i++)
{
stopwatchLong.Start();
//SND
_canbus.Write(cmd, cmd.Length, ref _bytesWritten);
stopwatchShort.Start();
Thread.Sleep(1);
//RCV
var answer = ReadContent();
stopwatchShort.Stop();
stopwatchLong.Stop();
DispatchIfNecessary(() =>
{
pbTimeMeasure.Value++;
});
}
Double resLong = Convert.ToDouble(stopwatchLong.ElapsedMilliseconds);
Double resLongAvg = resLong / loops;
Double resShort = Convert.ToDouble(stopwatchShort.ElapsedMilliseconds);
Double resShortAvg = resShort / loops;
DispatchIfNecessary(() =>
{
lbTotalResLong.Content = resLong.ToString();
lbTotalResShort.Content = resShort.ToString();
int length = 5;
if (resLongAvg.ToString().Length < 5)
{
length = resLong.ToString().Length;
}
if (resShortAvg.ToString().Length < length)
{
length = resShortAvg.ToString().Length;
}
lbAvgResLong.Content = resLongAvg.ToString().Substring(0,length);
lbAvgResShort.Content = resShortAvg.ToString().Substring(0,length);
});
}
I am creating a WPF application to collect logs. I am using different Backgroundworker to execute some scripts. Worker1 for script1, Worker2 for script2 and so on. When Backgroundworker completes RunworkerCompleted method get executed.
So, how can I wait for all the workers to complete? Once all these workers are complete, I need to update the UI thread.
You can try using Tasks.
Task t1 = Task.Run(() =>
{
// Do something
}
);
Task t2 = Task.Run(() =>
{
// Do something
}
);
Task t3 = Task.Run(() =>
{
// Do something
}
);
await Task.WhenAll(new Task[] { t1, t2, t3 }).ContinueWith((task) =>
{
// Do something when all three tasks have completed...
}
);
Here is a way to wait for all BackgroundWorker objects to get complete. I hope you are using C#:
static void Main(string[] args)
{
int noOfbackgroundWorker = 5;
WaitHandle[] waitHandles = new WaitHandle[noOfbackgroundWorker];
Stopwatch sw = new Stopwatch();
sw.Start();
for (int i = 0; i < noOfbackgroundWorker; i++)
{
var bg1 = new BackgroundWorker();
var handle = new EventWaitHandle(false, EventResetMode.ManualReset);
bg1.DoWork += delegate(object sender, DoWorkEventArgs e) { Thread.Sleep(i * 1000); };
bg1.RunWorkerCompleted += delegate(object sender, RunWorkerCompletedEventArgs e) { handle.Set(); };
waitHandles[i] = handle;
bg1.RunWorkerAsync();
}
WaitHandle.WaitAll(waitHandles);
Console.WriteLine("Done in "+sw.Elapsed.Seconds + " seconds");
Console.ReadKey();
}
Apart from above if there is low no of BackgroundWorker, just set a bool variable for each worker to map each worker complete status and call a common method from all RunworkerCompleted event handler that just has condition if(a && b && c.....) if passed then notify the UI.
As I say in my Task.Run vs BackgroundWorker conclusion:
anything like waiting for two separate background operations to complete before doing something else is much easier with Task.Run. Pretty much any time you have to coordinate background operations, Task.Run code is going to be much simpler!
(this is the conclusion of a series of blog posts comparing Task.Run to BackgroundWorker).
Worker1 for script1, Worker2 for script2 and so on.
You can do this with Task.Run:
Result DoWork(Script script) { ... }
IEnumerable<Script> scripts = ...;
var tasks = scripts.Select(x => Task.Run(() => DoWork(x))).ToList();
So, how can I wait for all the workers to complete? Once all these workers are complete, I need to update the UI thread.
Use await and Task.WhenAll:
var results = await Task.WhenAll(tasks);
... // Update UI with results
Hy, I just wanted to find out how to implement a loop that takes around 80 to 120ms (mostly 80ms) to execute. The loop has to execute for about 30 minutes... basically it is a SURF matching algorithm.
Currently I am using a System.Threading.Timer to create a timer that executes after every 90ms, but the problem is that since the computation time is variable, so after some time the stack overflows and the program closes.
I'm using WPF to create the GUI.
Is there a better way to implement such a loop using threading? Any help would be much appreciated! Thanks in advance.
//initialization
private System.Threading.Timer Visual_AR1;
Visual_AR1 = new System.Threading.Timer(new TimerCallback(Video_AR1), null, 0, 90);
private void Video_AR1(object state)
{
lock (this)
{
// SURF matching
modelImage_AR1 = new Image<Gray, byte>(droneControl_AR1.BitmapImage).Resize(1.8, INTER.CV_INTER_NN);
map_image_d1 = DrawMatches_gpu.GPU_0(wayx, modelImage_AR1, observedImage, pgpuObservedKeyPoints_imp, pgpuObservedDescriptors_imp, out matchTime_0, out pX1, out pY1);
Dispatcher.BeginInvoke((Action)delegate()
{
label4.Content = "Time Taken by GPU_0 : " + matchTime_0.ToString();
});
mask_selector_d1();
}
}
is this a viable solution ?
private Thread threadTask = null;
private void threadTask_Start()
{
if (threadTask == null) {
threadTask = new Thread(SURF);
threadTask.Start();
}
}
private void SURF()
{
while(true)
{
lock (this)
{
// SURF matching
modelImage_AR1 = new Image<Gray, byte>(droneControl_AR1.BitmapImage).Resize(1.8, INTER.CV_INTER_NN);
map_image_d1 = DrawMatches_gpu.GPU_0(wayx, modelImage_AR1, observedImage, pgpuObservedKeyPoints_imp, pgpuObservedDescriptors_imp, out matchTime_0, out pX1, out pY1);
Dispatcher.BeginInvoke((Action)delegate()
{
label4.Content = "Time Taken by GPU_0 : " + matchTime_0.ToString();
});
mask_selector_d1();
}
thread.sleep(40);
}
}
Instead of making the timer tick perform the work, make the timer tick queue up a job and have something else (presumably threads from the thread pool) consume the jobs. You can use a semaphore to throttle the number of jobs running simultaneously and you can examine the state of the queue to avoid this sort of over-commit problem.
I'm web developer and I'm trying to step into multithreading programming.
On one form I'm trying to run a method computing values in a second thread using asynchronous delegates.
I also want a progress bar showing actual progress in UI thread been notified.
delegate void ShowProgressDelegate(int total, int value);
delegate void ComputeDelegate(int value);
//Some method simulating sophisticated computing process
private void Compute(int value)
{
ShowProgress(value, 0);
for (int i = 0; i <= value; i++)
{
ShowProgress(value, i);
}
}
//Method returning values into UI thread
private void ShowProgress(int total, int value)
{
if (!this.InvokeRequired)
{
ComputeButton.Text = value.ToString();
ProgressBar.Maximum = total;
ProgressBar.Value = value;
}
else
{
ShowProgressDelegate showDel = new ShowProgressDelegate(ShowProgress);
this.BeginInvoke(showDel, new object[] { total, value });
}
}
//firing all process
private void ComputeButton_Click(object sender, EventArgs e)
{
ComputeButton.Text = "0";
ComputeDelegate compDel = new ComputeDelegate(Compute);
compDel.BeginInvoke(100000, null, null);
}
When I run this, everything is computing without any problem except it is still running in UI thread (I suppose so, because it freezes when I click some button on the form).
Why? I also attach buildable sample project (VS2010) with same code: http://osmera.com/windowsformsapplication1.zip
Thanks for helping neewbie.
In the code you've shown, you're doing nothing other than updating the progress bar - so there are thousands of UI messages to marshal, but nothing significant happening in the non-UI thread.
If you start simulating real work in Compute, you'll see it behave more reasonably, I suspect. You need to make sure you don't swamp the UI thread with progress updates like you are doing now.