Page 1 of 1

C# Parallel.For

Posted: Thu Dec 18, 2014 6:21 pm
by Xaos
Hey guys. I decided to use Parallel.For for one of my for loops to make it faster, but for some reason once I hook up the Parallel.For, I get a System.ArgumentException error cast and it says the Source array was not long enough, even though it works perfectly fine for a normal for loop. None of that code changed.

Re: C# Parallel.For

Posted: Thu Dec 18, 2014 7:02 pm
by a_bertrand
You should provide us the code to try to help you. Just like that it's impossible to say what's going on.

Re: C# Parallel.For

Posted: Thu Dec 18, 2014 8:21 pm
by Xaos

Code: Select all

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace EconomicSimulator
{
    class Citizen
    {
        public static int Population;
        public static List<long> citizenList = new List<long>();

        public static void Populate()
        {
            long income;
            Random rnd = new Random();
            Population = rnd.Next(17800000, 47800000); //Creating the population, some # between those numbers

            Parallel.For(0, Population, i => //Loop through the population
            {
                double incomeChance = (rnd.Next(0, 1200000)); //Figure out which income bracket said 'person' is in
                if (incomeChance <= 1)
                {
                    income = Math.Abs(10000000 * rnd.Next(10000, 80000));
                    citizenList.Add(income);
                    // Over $10,000,000
                }
                else if (incomeChance <= 2)
                {
                    income = Math.Abs(1000 * rnd.Next(5000, 10000));
                    citizenList.Add(income);
                    // $5,000,000 to $10,000,000
                }
                else if (incomeChance > 3 && incomeChance <= 7)
                {
                    income = Math.Abs(1000 * rnd.Next(1500, 2000));
                    citizenList.Add(income);
                    // $1,500,000 to $2,000,000
                }
                else if (incomeChance > 7 && incomeChance <= 30)
                {
                    income = Math.Abs(1000 * rnd.Next(2000, 5000));
                    citizenList.Add(income);
                    // $2,000,000 to $5,000,000
                }
                else if (incomeChance > 30 && incomeChance <= 86)
                {
                    income = Math.Abs(1000 * rnd.Next(1000, 1500));
                    citizenList.Add(income);
                    // $1,000,000 to $1,500,000
                }
                else if (incomeChance > 86 && incomeChance <= 136)
                {
                    income = Math.Abs(100 * rnd.Next(5000, 10000));
                    citizenList.Add(income);
                    // $500,000 to $1,000,000
                }
                else if (incomeChance > 136 && incomeChance <= 256)
                {
                    income = Math.Abs(100 * rnd.Next(2000, 5000));
                    citizenList.Add(income);
                    // $200,000 to $500,000
                }
                else if (incomeChance > 256 && incomeChance <= 10606)
                {
                    income = Math.Abs(10 * rnd.Next(2500, 3000));
                    citizenList.Add(income);
                    // $25,000 to $30,000
                }
                else if (incomeChance > 10606 && incomeChance <= 50606)
                {
                    income = Math.Abs(10 * rnd.Next(2000, 2500));
                    citizenList.Add(income);
                    // $20,000 to $25,000
                }
                else if (incomeChance > 50606 && incomeChance <= 100606)
                {
                    income = Math.Abs(rnd.Next(1, 5000));
                    citizenList.Add(income);
                    // $1 to $5,000
                }
                else if (incomeChance > 100606 && incomeChance <= 280606)
                {
                    income = Math.Abs(10 * rnd.Next(4000, 5000));
                    citizenList.Add(income);
                    // $40,000 to $50,000
                }
                else if (incomeChance > 280606 && incomeChance <= 345606)
                {
                    income = Math.Abs(10 * rnd.Next(7500, 10000));
                    citizenList.Add(income);
                    // $75,000 to $100,000
                }
                else if (incomeChance > 345606 && incomeChance <= 426606)
                {
                    income = Math.Abs(10 * rnd.Next(1500, 2000));
                    citizenList.Add(income);
                    // $15,000 to $20,000
                }
                else if (incomeChance > 426006 && incomeChance <= 621006)
                {
                    income = Math.Abs(rnd.Next(5000, 10000));
                    citizenList.Add(income);
                    // $5,000 to $10,000
                }
                else if (incomeChance > 621006 && incomeChance <= 710006)
                {
                    income = Math.Abs(10 * rnd.Next(1000, 1500));
                    citizenList.Add(income);
                    // $10,000 to $15,000
                }
                else if (incomeChance > 710006 && incomeChance <= 780006)
                {
                    income = Math.Abs(10 * rnd.Next(3000, 4000));
                    citizenList.Add(income);
                    // $30,000 to $40,000
                }
                else if (incomeChance > 780006 && incomeChance <= 800006)
                {
                    income = Math.Abs(100 * rnd.Next(1000, 2000));
                    citizenList.Add(income);
                    // $100,000 to $200,000
                }
                else if (incomeChance > 800006)
                {
                    income = Math.Abs(10 * rnd.Next(5000, 7500));
                    citizenList.Add(income);
                    // $50,000 to $75,000
                }
            });
        }
    }
}
Here you go, thought maybe the above would be enough and this is a common err or something. But I have the Parallel.For, and it throws the exception. With a normal for loop it doesn't.

Re: C# Parallel.For

Posted: Thu Dec 18, 2014 11:06 pm
by Jackolantern
I am not that familiar with the TPL in .NET, but does this require synchronization or some other type of thread-safety on the citizenList, Alan? If so, Xaos, you may want to consider switching to one of the ready-made thread-safe collections. Unchecked multithreading can cause all kinds of headaches with collections, such as doubling values, missing values, etc.

Also, Xaos, have you actually checked that this FOR loop is causing performance problems? I do realize it is running millions of times, but that may actually finish at a decent rate since little work is being done inside of it. It is generally a best practice to not start worrying about optimization until you are sure there is a problem. If it is completing in a half a second or so, I would see little point in investing it making it concurrent.

Re: C# Parallel.For

Posted: Thu Dec 18, 2014 11:57 pm
by Xaos
Well I was hoping that this would work so I could see if this could make it faster. But ill check into thoee you linker.

Re: C# Parallel.For

Posted: Sat Dec 20, 2014 4:57 am
by a_bertrand
Indeed, lists are not thread safe and here this code will access the list from multiple threads at the same time. Either lock every access of the list, or use a thread safe collection. You will not be 100% pleased by those collections however as they are not the same as the non thread safe one.

Re: C# Parallel.For

Posted: Sun Dec 21, 2014 11:26 pm
by Jackolantern
You will also notice quite a large step backwards in performance back towards the sequential access. Almost all of your code inside the parallel for loop would be considered critical, so a ton of that is going to end up becoming sequential to maintain locks.

Re: C# Parallel.For

Posted: Sun Dec 21, 2014 11:56 pm
by Xaos
Ohh, gotcha guys. How do you guys recommend optimizing? I'm basically running this for loop, finding the mean, finding the median, then taking a % of each value in an array (from the for loop) and taking a %, adding it to anohter value and changing it in the array.

Re: C# Parallel.For

Posted: Tue Dec 23, 2014 7:43 am
by Jackolantern
How long is it taking to complete as-is?

Re: C# Parallel.For

Posted: Tue Dec 23, 2014 7:57 am
by Xaos
About 20-30 minutes for a simulation of 17.8 million - 47.8 million.