WPF strange behavior with thread adn invoke to update progress bar - c#

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.

Related

MaxDegreeOfParallelism blocks the Main thread?

I have the next code, and works fine:
private void BtBasicIntroClick(object sender, EventArgs e)
{
var stopwatch = new Stopwatch();
stopwatch.Reset();
stopwatch.Start();
var executionDataflowBlockOptions = new ExecutionDataflowBlockOptions
{
//TaskScheduler = TaskScheduler.FromCurrentSynchronizationContext(),
MaxDegreeOfParallelism = 1
};
var actionBlock = new ActionBlock<int>(s =>
{
//comboBox1.Items.Add((s*3).ToString());
Invoke(new Action(() => comboBox1.Items.Add((s * 3).ToString())));
}, executionDataflowBlockOptions);
var numeros = Enumerable.Range(0, 40000);
foreach (var numero in numeros)
{
actionBlock.Post(numero);
}
Task.Factory.StartNew(() =>
{
actionBlock.Completion.ContinueWith(delegate
{
stopwatch.Stop();
if (InvokeRequired)
{
Invoke(new Action(() =>
label1.Text = stopwatch.ElapsedMilliseconds.ToString(CultureInfo.InvariantCulture)));
}
});
actionBlock.Complete();
actionBlock.Completion.Wait();
});
}
The Windows Forms works fine... the proccess doesn't block the UI
But if I change the MaxDgreeOfParallelism to other value (2 or 3 or 4...) the UI is blocked until the proccess finish.
I've see the Parallel Tasks window and the Thread Window in Visual Studio and in both cases everything works in Worked Threads, but in the latter case (When the MaxDgreeOfParallelism it's different from 1 ) the UI don't respond until the proccess finish
Why?
When I try your code, the UI is blocked the whole time, even with MaxDegreeOfParallelism = 1. That's because all your block does is to call Invoke(), which blocks the UI thread.
It's possible that under some circumstances, one thread calling Invoke() over and over won't be enough to block the UI thread completely, but 2 threads almost certainly will.
So, what you're trying to do doesn't make any sense. You're not going to gain anything from using dataflow, or anything similar.
What you should do to fix this is not to have thousands of items in the UI. No human is going to go though such huge list anyway.

Parallel.ForEach freezing on last loop [duplicate]

More newbie questions:
This code grabs a number of proxies from the list in the main window (I couldn't figure out how to make variables be available between different functions) and does a check on each one (simple httpwebrequest) and then adds them to a list called finishedProxies.
For some reason when I press the start button, the whole program hangs up. I was under the impression that Parallel creates separate threads for each action leaving the UI thread alone so that it's responsive?
private void start_Click(object sender, RoutedEventArgs e)
{
// Populate a list of proxies
List<string> proxies = new List<string>();
List<string> finishedProxies = new List<string>();
foreach (string proxy in proxiesList.Items)
{
proxies.Add(proxy);
}
Parallel.ForEach<string>(proxies, (i) =>
{
string checkResult;
checkResult = checkProxy(i);
finishedProxies.Add(checkResult);
// update ui
/*
status.Dispatcher.Invoke(
System.Windows.Threading.DispatcherPriority.Normal,
new Action(
delegate()
{
status.Content = "hello" + checkResult;
}
)); */
// update ui finished
//Console.WriteLine("[{0}] F({1}) = {2}", Thread.CurrentThread.Name, i, CalculateFibonacciNumber(i));
});
}
I've tried using the code that's commented out to make changes to the UI inside the Parallel.Foreach and it makes the program freeze after the start button is pressed. It's worked for me before but I used Thread class.
How can I update the UI from inside the Parallel.Foreach and how do I make Parallel.Foreach work so that it doesn't make the UI freeze up while it's working?
Here's the whole code.
You must not start the parallel processing in your UI thread. See the example under the "Avoid Executing Parallel Loops on the UI Thread" header in this page.
Update: Or, you can simply create a new thread manuall and start the processing inside that as I see you have done. There's nothing wrong with that too.
Also, as Jim Mischel points out, you are accessing the lists from multiple threads at the same time, so there are race conditions there. Either substitute ConcurrentBag for List, or wrap the lists inside a lock statement each time you access them.
A good way to circumvent the problems of not being able to write to the UI thread when using Parallel statements is to use the Task Factory and delegates, see the following code, I used this to iterate over a series of files in a directory, and process them in a Parallel.ForEach loop, after each file is processed the UI thread is signaled and updated:
var files = GetFiles(directoryToScan);
tokenSource = new CancellationTokenSource();
CancellationToken ct = tokenSource.Token;
Task task = Task.Factory.StartNew(delegate
{
// Were we already canceled?
ct.ThrowIfCancellationRequested();
Parallel.ForEach(files, currentFile =>
{
// Poll on this property if you have to do
// other cleanup before throwing.
if (ct.IsCancellationRequested)
{
// Clean up here, then...
ct.ThrowIfCancellationRequested();
}
ProcessFile(directoryToScan, currentFile, directoryToOutput);
// Update calling thread's UI
BeginInvoke((Action)(() =>
{
WriteProgress(currentFile);
}));
});
}, tokenSource.Token); // Pass same token to StartNew.
task.ContinueWith((t) =>
BeginInvoke((Action)(() =>
{
SignalCompletion(sw);
}))
);
And the methods that do the actual UI changes:
void WriteProgress(string fileName)
{
progressBar.Visible = true;
lblResizeProgressAmount.Visible = true;
lblResizeProgress.Visible = true;
progressBar.Value += 1;
Interlocked.Increment(ref counter);
lblResizeProgressAmount.Text = counter.ToString();
ListViewItem lvi = new ListViewItem(fileName);
listView1.Items.Add(lvi);
listView1.FullRowSelect = true;
}
private void SignalCompletion(Stopwatch sw)
{
sw.Stop();
if (tokenSource.IsCancellationRequested)
{
InitializeFields();
lblFinished.Visible = true;
lblFinished.Text = String.Format("Processing was cancelled after {0}", sw.Elapsed.ToString());
}
else
{
lblFinished.Visible = true;
if (counter > 0)
{
lblFinished.Text = String.Format("Resized {0} images in {1}", counter, sw.Elapsed.ToString());
}
else
{
lblFinished.Text = "Nothing to resize";
}
}
}
Hope this helps!
If anyone's curious, I kinda figured it out but I'm not sure if that's good programming or any way to deal with the issue.
I created a new thread like so:
Thread t = new Thread(do_checks);
t.Start();
and put away all of the parallel stuff inside of do_checks().
Seems to be doing okay.
One problem with your code is that you're calling FinishedProxies.Add from multiple threads concurrently. That's going to cause a problem because List<T> isn't thread-safe. You'll need to protect it with a lock or some other synchronization primitive, or use a concurrent collection.
Whether that causes the UI lockup, I don't know. Without more information, it's hard to say. If the proxies list is very long and checkProxy doesn't take long to execute, then your tasks will all queue up behind that Invoke call. That's going to cause a whole bunch of pending UI updates. That will lock up the UI because the UI thread is busy servicing those queued requests.
This is what I think might be happening in your code-base.
Normal Scenario: You click on button. Do not use Parallel.Foreach loop. Use Dispatcher class and push the code to run on separate thread in background. Once the background thread is done processing, it will invoke the main UI thread for updating the UI. In this scenario, the background thread(invoked via Dispatcher) knows about the main UI thread, which it needs to callback. Or simply said the main UI thread has its own identity.
Using Parallel.Foreach loop: Once you invoke Paralle.Foreach loop, the framework uses the threadpool thread. ThreadPool threads are chosen randomly and the executing code should never make any assumption on the identity of the chosen thread. In the original code its very much possible that dispatcher thread invoked via Parallel.Foreach loop is not able to figure out the thread which it is associated with. When you use explicit thread, then it works fine because the explicit thread has its own identity which can be relied upon by the executing code.
Ideally if your main concern is all about keeping UI responsive, then you should first use the Dispatcher class to push the code in background thread and then in there use what ever logic you want to speedup the overall execution.
if you want to use parallel foreach in GUI control like button click etc
then put parallel foreach in Task.Factory.StartNew
like
private void start_Click(object sender, EventArgs e)
{
await Task.Factory.StartNew(() =>
Parallel.ForEach(YourArrayList, (ArraySingleValue) =>
{
Console.WriteLine("your background process code goes here for:"+ArraySingleValue);
})
);
}//func end
it will resolve freeze/stuck or hang issue

Problems with waiting for the threads to end

I'm doing some C# threading. No problems starting the threads and transferring data to them, but I have a problem with waiting for them to end.
My code is shown below. I'm using Join() to wait for the threads to end, but for some reason my code doesn't work.
The main thread (i.e. the for loop) isn't blocked despite calling Join() on all the active threads.
Any idea what I'm doing wrong?
List<Thread> calculationThreads = new List<Thread>();
foreach (string calculation in calculations)
{
if (calculationThreads.Count < 5)
{
Thread calculationThread = new Thread(DoCalculation);
calculationThreads.Add(calculationThread);
calculationThread.Start(threadData);
}
else
{
// Wait for the threads to complete
foreach (Thread calculationThread in calculationThreads)
{
calculationThread.Join();
}
}
}
The first problem is your handling of the else case. If there is already five threads the code will wait for the threads to finish, but the task that it was trying to add is never added. It will just throw away that task and go on to the next.
The second problem is that you don't remove any threads from the list, so once it reaches five threads, it will wait forever. If the first problem didn't discard the rest of the tasks, your program would just lock up.
Also, you are wasting processing time by waiting for all five threads to finish before continuing the work, but that's a smaller problem.
I would go for some approach where I just calculate how many threads I've started and in the end of each thread I decrease the counter.
Then in the beginning of your loop you can have
while(counter >= 5)
{
//Wait
}
You can have a while loop that waits for all the threads to end.
List<Thread> calculationThreads = new List<Thread>();
foreach (string calculation in calculations)
{
if (calculationThreads.Count < 5)
{
Thread calculationThread = new Thread(DoCalculation);
calculationThreads.Add(calculationThread);
calculationThread.Start(threadData);
}
else
{
// Wait for the threads to complete
while(calculationThread.Any(x => x.IsAlive)){}
// Clearing the list
calculationThread.Clear();
}
}
If you want to keep the threads for after the for loop you should have another list for storing the threads.
How many calculations are you providing to the method?
Reading the code, if you provide 4 calculations you'll start 4 threads but never actually go to the code where you do a thread.Join().
Move the thread.join loop outside the if else statement.
List<Thread> calculationThreads = new List<Thread>();
foreach (string calculation in calculations)
{
if (calculationThreads.Count < 5)
{
Thread calculationThread = new Thread(DoCalculation);
calculationThreads.Add(calculationThread);
calculationThread.Start(threadData);
}
}
foreach (Thread calculationThread in calculationThreads)
{
calculationThread.Join();
}

Thread runs slow when Invoke UI-Element

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;
}
}

when parent thread sleep does sub threads also sleep?

when parent thread sleep does sub threads also sleep ?
Now main thread is UI
I create 20 sub threads inside main thread with task factory (lets call threads 2)
Inside of this 20 sub threads i create another 10 sub threads again with sub factory (lets call threads 3)
Now inside of this threads 2 i have infinite loop. Inside of infinite loop checking whether threads 3 completed or not. If completed dispose completed thread and start another thread. I am using 250 ms sleep for each checking inside infinite while loop. So when threads 2 in sleep does also threads 3 sleep or they are independent. Here the code you can see.
while (true)
{
int irActiveThreadCount = 0;
int irFinishedLast = -1;
for (int i = 0; i < irPerMainSiteThreadCount; i++)
{
if (MainSitesTaskList[irWhichMainTask, i] == null)
{
irFinishedLast = i;
break;
}
if (MainSitesTaskList[irWhichMainTask, i].IsCompleted == true)
{
irFinishedLast = i;
break;
}
}
for (int i = 0; i < irPerMainSiteThreadCount; i++)
{
if (MainSitesTaskList[irWhichMainTask, i] != null)
if (MainSitesTaskList[irWhichMainTask, i].IsCompleted == false)
{
irActiveThreadCount++;
}
}
if (irFinishedLast > -1)
{
var newTask = Task.Factory.StartNew(() =>
{
fcStartSubPageCrawl(srMainSiteURL, srMainSiteId, irWhichMainTask);
});
lock (lockerMainSitesArray)
{
if (MainSitesTaskList[irWhichMainTask, irFinishedLast] != null)
MainSitesTaskList[irWhichMainTask, irFinishedLast].Dispose();
MainSitesTaskList[irWhichMainTask, irFinishedLast] = newTask;
}
}
Thread.Sleep(250);
srQuery = "myquery";
using (DataSet dsTemp = DbConnection.db_Select_Query(srQuery))
{
if (dsTemp != null)
if (dsTemp.Tables.Count > 0)
if (dsTemp.Tables[0].Rows.Count == 0)
{
break;
}
}
}
There's no such thing as a "parent" thread really. One thread starts another, but then there's no particular relationship between them. For example, the starting thread can terminate without any of the new threads dying.
The starting thread sleeping definitely doesn't affect any other thread.
There is no concept of parent and child threads. One implication of this is that the child threads don't sleep when the parent thread sleeps.
Thread.Sleep(...)
only suspends the current Thread.
check here: Thread.Sleep Method
so all other threads will keep working.
Each thread is always totally independant. The only possible connection between threads is that when all the non-background thread finish, the program ends, so the background threads die. If a thread sleeps, the other threads continue working (and probably go faster, because there is one less thread working). If you need to sync threads, there are various classes to do it (in general locks (not a class), mutexes, semaphores...)
The others are right, there is no concept of “parent threads” in .Net. And waiting on one thread doesn't cause other threads to wait (unless there is some synchronization involved, like using locks).
But there's another point: your code doesn't create new threads, at least not necessarily. When you call Task.Factory.StartNew(), the task is usually scheduled on a thread pool thread. If there isn't any thread available and the number of threads didn't reach the maximum allowed number yet, new thread is created. But in other cases, it isn't. The task is either going to reuse existing idle thread, or it's going to wait, until one becomes available.

Categories

Resources