Showing progress value from a list of tasks through ProgressBar - c#

My title may make my question sound confusing, but it is not.
I have a list of tasks to do and a ProgressBar. When I loop through the list of tasks, I want to display the progress through a ProgressBar:
double percentage;
for(int i = 0; i < tasks.Count; i++)
{
percentage = (double)i + 1 / (double)tasks.Count;
this.Invoke((MethodInvoker)delegate
{
progressBar1.Value = (int)Math.Round(percentage * 100);
});
// Do tasks here...
}
So if I have say, 20 tasks I want progressBar1 to have the value of 5 ((1 / 20) * 100), then when it loops through again it has the value of 10, 15 and so on. The method that I am using right now does not work properly, on the first task progressBar1 has a value of 0, then when it loops through again it has the value of 100. Is there a way of doing what I am trying to achieve?
Thanks.

for(int i = 0; i < tasks.Count; i++)
{
double percentage = (double)(i + 1) / (double)tasks.Count;
Action<double> update = p =>
{
progressBar1.Value = (int)Math.Round(p * 100);
};
this.Invoke(update, percentage);
// Do tasks here...
}

Your code should essentially work, however I'd guess your UI just isn't able to update in time (i.e. there's no context switch happening and you return control only once you're done). I don't have that much experience involving C#, multithreading and UI coding, so I might be a bit off here.
What I'd try to do here is sleeping a moment (even essentially 0 seconds should do the trick) once you start doing your tasks within the tasks thread.
A bit off-topic: I'd like to mention that you're overcomplicating it a bit. Just set the maximum value of your progress bar to the number of tasks, then increase it's value 1 by 1, which removes quite a bit of obsolete math within that loop.
Edit: Yeah, just noticed Darin's answer and he's right: You're missing brackets as well, causing your percentage calculation going wrong.
But keep in mind that doing it that way might cause your total percentage to be slightly off due to precision errors (won't matter a lot depending on number of tasks; but you might not be able to hit exactly 100%).

Related

How to loop a list while using Multi-threading in c#

I have a List to loop while using multi-thread,I will get the first item of the List and do some processing,then remove the item.
While the count of List is not greater than 0 ,fetch data from data.
In a word:
In have a lot of records in my database.I need to publish them to my server.In the process of publishing, multithreading is required and the number of threads may be 10 or less.
For example:
private List<string> list;
void LoadDataFromDatabase(){
list=...;//load data from database...
}
void DoMethod()
{
While(list.Count>0)
{
var item=list.FirstOrDefault();
list.RemoveAt(0);
DoProcess();//how to use multi-thread (custom the count of theads)?
if(list.Count<=0)
{
LoadDataFromDatabase();
}
}
}
Please help me,I'm a beginner of c#,I have searched a lot of solutions, but no similar.
And more,I need to custom the count of theads.
Should your processing of the list be sequential? In other words, cannot you process element n + 1 while not finished yet processing of element n? If this is your case, then Multi-Threading is not the right solution.
Otherwise, if your processing elements are fully independent, you can use m threads, deviding Elements.Count / m elements for each thread to work on
Example: printing a list:
List<int> a = new List<int> { 1, 2, 3, 4,5 , 6, 7, 8, 9 , 10 };
int num_threads = 2;
int thread_elements = a.Count / num_threads;
// start the threads
Thread[] threads = new Thread[num_threads];
for (int i = 0; i < num_threads; ++i)
{
threads[i] = new Thread(new ThreadStart(Work));
threads[i].Start(i);
}
// this works fine if the total number of elements is divisable by num_threads
// but if we have 500 elements, 7 threads, then thread_elements = 500 / 7 = 71
// but 71 * 7 = 497, so that there are 3 elements not processed
// process them here:
int actual = thread_elements * num_threads;
for (int i = actual; i < a.Count; ++i)
Console.WriteLine(a[i]);
// wait all threads to finish
for (int i = 0; i < num_threads; ++i)
{
threads[i].Join();
}
void Work(object arg)
{
Console.WriteLine("Thread #" + arg + " has begun...");
// calculate my working range [start, end)
int id = (int)arg;
int mystart = id * thread_elements;
int myend = (id + 1) * thread_elements;
// start work on my range !!
for (int i = mystart; i < myend; ++i)
Console.WriteLine("Thread #" + arg + " Element " + a[i]);
}
ADD For your case, (uploading to server), it is the same as the code obove. You assign a number of threads, assigning each thread number of elements (which is auto calculated in the variable thread_elements, so you need only to change num_threads). For method Work, all you need is replacing the line Console.WriteLine("Thread #" + arg + " Element " + a[i]); with you uploading code.
One more thing to keep in mind, that multi-threading is dependent on your machine CPU. If your CPU has 4 cores, for example, then the best performance obtained would be 4 threads at maximum, so that assigning each core a thread. Otherwise, if you have 10 threads, for example, they would be slower than 4 threads because they will compete on CPU cores (Unless the threads are idle, waiting for some event to occur (e.g. uploading). In this case, 10 threads can run, because they don't take %100 of CPU usage)
WARNING: DO NOT modify the list while any thread is working (add, remove, set element...), neither assigning two threads the same element. Such things cause you a lot of bugs and exceptions !!!
This is a simple scenario that can be expanded in multiple ways if you add some details to your requirements:
IEnumerable<Data> LoadDataFromDatabase()
{
return ...
}
void ProcessInParallel()
{
while(true)
{
var data = LoadDataFromDatabase().ToList();
if(!data.Any()) break;
data.AsParallel().ForEach(ProcessSingleData);
}
}
void ProcessSingleData(Data d)
{
// do something with data
}
There are many ways to approach this. You can create threads and partition the list yourself or you can take advantage of the TPL and utilize Parallel.ForEach. In the example on the link you see a Action is called for each member of the list being iterated over. If this is your first taste of threading I would also attempt to do it the old fashioned way.
Here my opinion ;)
You can avoid use multithread if youur "List" is not really huge.
Instead of a List, you can use a Queue (FIFO - First In First Out). Then only use Dequeue() method to get one element of the Queue, DoSomeWork and get the another. Something like:
while(queue.Count > 0)
{
var temp = DoSomeWork(queue.Dequeue());
}
I think that this will be better for your propose.
I will get the first item of the List and do some processing,then remove the item.
Bad.
First, you want a queue, not a list.
Second, you do not process then remove, you remove THEN process.
Why?
So that you keep the locks small. Lock list access (note you need to synchonize access), remove, THEN unlock immediately and then process. THis way you keep the locks short. If you take, process, then remove - you basically are single threaded as you have to keep the lock in place while processing, so the next thread does not take the same item again.
And as you need to synchronize access and want multiple threads this is about the only way.
Read up on the lock statement for a start (you can later move to something like spinlock). Do NOT use threads unless you ahve to put schedule Tasks (using the Tasks interface new in 4.0), which gives you more flexibility.

Progress bar withing a foreach loop

I have a method that iterates through an array of music notes and plays them one after the other. I have created a progress bar that will show the status of the foreach loop.
The problem is that the progress bar is not filling up to 100% but approximately till 85%. I have also noted that the progress bar is progressing roughly, I think that this could be because the steps are large. Any ideas on how can I optimize this progress bar, pb is my instance of the progress bar, Thanks
public void PlayAll()
{
pb.Maximum = Convert.ToInt32(CountTotalDuration()); //Total lenght of the full song.
pb.Step = Convert.ToInt32(CountTotalDuration()) / Convert.ToInt32(ListSize()); //Total lenght of each note making up the song.
foreach (MusicNote m in list)
{
m.sp.Stop();
m.sp.Play();
Thread.Sleep(m.NoteDuration*100);
pb.PerformStep();
}
}
Your issue is from rounding errors in your steps. Lets look at a simple example, say you have a CountTotalDuration() of 100 and a ListSize() of 7
because you have two integer numbers / does integer division and throws away any remainder so 100 / 7 equals 14 (instead of 14.285714 with 285714 repeating). That makes your step size 14, so after doing 7 steps your total value you have reached is 98 and you would see 98% on the toolbar.
Since CountTotalDuration() appears to be the sum of NoteDuration the way to fix this is to not use equal step sizes each step. Instead, just set the max to the total duration and increment the bar by the tote duration. This will make the bar jump in proportion to the position in the song based on note length.
public void PlayAll()
{
pb.Maximum = Convert.ToInt32(CountTotalDuration()); //Total lenght of the full song.
int currentCount = 0; //Initialize our counter to 0.
foreach (MusicNote m in list)
{
m.sp.Stop();
m.sp.Play();
Thread.Sleep(m.NoteDuration*100);
//Increment the counter proportional to the length of the note.
currentCount += m.NoteDuration;
//Set the progress bar using our calculated position.
pb.Value = currentCount;
}
}
You still are going to have big jumps when long notes play, the only way to solve that is not use Thread.Sleep(m.NoteDuration*100); and instead use multiple shorter pauses and update the bar in between those pauses. Also Thread.Sleep may not be the best way to pause the loop, but I don't know what the best alternative to use instead would be, it depends on a lot of details which you have not shared with us.
You could also have similar behavior to your old method and have the note jump by 1 for each note played and just make the bar's maximum equal to the number of notes you will play.
public void PlayAll()
{
pb.Maximum = list.Length; //Or equivalent, perhaps ListSize()?
pb.Step = 1;
foreach (MusicNote m in list)
{
m.sp.Stop();
m.sp.Play();
Thread.Sleep(m.NoteDuration*100);
pb.PerformStep();
}
}
This will give you more even jumps per note but if the song is only a few notes long those even jumps could still be very large.
it sounds strange, I didn't find the problem, but I suggest you can try as this:
public void PlayAll()
{
pb.Maximum = Convert.ToInt32(ListSize()); //Total lenght of the full song.
pb.Step = 1;
int i = 1;
foreach (MusicNote m in list)
{
m.sp.Stop();
m.sp.Play();
Thread.Sleep(m.NoteDuration * 100);
pb.Value = i++;
}
}
further more, maybe you should use multithreading to improve the user experience, because Thread.Sleep() makes the form like dead.

Progress bar not updating as expected

The progress bar is going to 70 just fine. It's when I go to update it when the loop starts that the bar doesn't move.
int count = finalFiles.Length; //finalFiles in an array and it varies in size.
int current = 0;
private void uploadWorker_DoWork(object sender, DoWorkEventArgs e)
{
uploadWorker.ReportProgress(20);
DoSomeWork();
uploadWorker.ReportProgress(50);
DoMoreWork();
uploadWorker.ReportProgress(70);
foreach (string file in finalFiles)
{
current++;
doProcess();
uploadWorker.ReportProgress(current / count * 30 + 70);
}
}
Again, the problem is that the progress bar is not updating once it reaches 70. It just doesn't move. The form does not lock up by the way because I'm using background worker.
Does anyone know why that is?
You have an integer current, and an integer count. Since count is bigger, when you do the division it is always 0 (integer division) until current reaches current. You should either make count a double/decimal, or cast one of the two to a double/decimal before doing the division.
I don't know what doProcess() does, but shouldn't you increment current in your foreach?
Looks like you need some parentheses somewhere e.g.
foreach (string file in finalFiles)
{
doProcess();
uploadWorker.ReportProgress( ((current / count) * 30) + 70);
}
OK I don't know that maths you need (sorry, I'm in the middle of something else here), but I would suggest you put parentheses in the calculation, since it looks to me like that could be an issue.

Multi-threading Report Progress Not Working

I've recently started working with multi-threaded Winform applications and have run up against a problem I don't understand.
Basically, when I try to have a background worker report its progress and that progress comes from a calculation, it is always zero.
//making background worker
BackgroundWorker myJanitor = new BackgroundWorker();
myJanitor.WorkerSupportsCancellation = true;
myJanitor.WorkerReportsProgress = true;
myJanitor.DoWork += new DoWorkEventHandler(cleanContactList);
myJanitor.ProgressChanged += new ProgressChangedEventHandler(myCleaningWorker_ProgressChanged);
myJanitor.RunWorkerAsync();
The 'cleanContactList' method loops through a DataGridView's rows, during which I try something like this:
int percentComplete = (myRow.Index / contactGridView.Rows .Count ) * 100;
(sender as BackgroundWorker).ReportProgress(percentComplete);
Frustratingly, percentComplete will ALWAYS be zero. If I debug it I can see that there is an actual calculation occurring (e.g. [2000/10000]*100) but the result is always zero.
What am I missing here? If I replace the calculation with, say, a Random.Next(0,100) call it updates fine.
Try index * 100/count. I think you're dividing two ints leading to 0 then multiplying by 100.
For example, this:
int index = 50;
int count = 100;
int percent = index/count * 100;
int percent2 = index * 100/count;
Console.WriteLine("{0} & {1}", percent, percent2);
Outputs 0 & 50.
[2000/10000]*100) but the result is always zero
C# 101 for beginners. Actually more programming - it is the same in most languages that know variable types.
Operations happen on the alrgest most precice variable type involved.
2000 (integer) / 10000 (integer) is aninteger result rounded = 0
I suggest you FIRST multiply, THEN divide. Or choose a different variable type either in the variables, or in the formula (i.e. [(float)2000 will convert the whole formulat to use floats.

Deriving a curve from datapoints

I manually adjust the thread count:
if (items.Count == 0) { threads = 0; }
else if (items.Count < 1 * hundred) { threads = 1; }
else if (items.Count < 3 * hundred) { threads = 2; }
else if (items.Count < 5 * hundred) { threads = 4; }
else if (items.Count < 10 * hundred) { threads = 8; }
else if (items.Count < 20 * hundred) { threads = 11; }
else if (items.Count < 30 * hundred) { threads = 15; }
else if (items.Count < 50 * hundred) { threads = 30; }
else threads = 40;
I need a function that returns the necessary/optimized thread count.
Ok, now forget above. I need a graph curve to plot. I give the coords, function plots the curve. Imagine the point(0,0) and point(5,5) -in (x,y) form. It should be straight line. So then I can measure x for y=3.
What happens if I give the points (0,0), (2,3), (8,10), (15,30) and (30,50). It will be a curve like thing. Now can I calculate x for given y or vice versa?
I think you get the idea. Should I use MathLab or could it be done in C#?
You're looking for curve fitting, or the derivation of a function describing a curve from a set of data points. If you're looking to do this once, from a constant set of data, Matlab would do the job just fine. If you want to do this dynamically, there are libraries and algorithms out there.
Review the Wikipedia article on linear regression. The least squares approach mentioned in that article is pretty common. Look around, and you'll find libraries and code samples using that approach.
You can probably make that run faster by reordering the tests (and using nested if). But that's not a smooth function, there's not likely to be any simpler description.
Or are you trying to find a smooth function that passes near those points?
You could use a linear regression; you would get something like this:
So I would probably encode it in C# like this:
int threads = (int) Math.Ceiling(0.0056*items.Count + 0.5);
I used Math.Ceiling to ensure that you don’t get 0 when the input isn’t 0. Of course, this function gives you 1 even if the input is 0; if that matters, you can always catch that as a special case, or use Math.Round instead.
However, this means the number of threads will go up continuously. It will not level out at 40. If that’s what you want, you might need to research different kinds of regression.

Categories