1

I have the following c# code:

        int[] ns = new int[4] { 100, 500, 1000, 5000 };
        int[] ks = new int[5] { 5, 10, 15, 80, 160 };
        int[] rs = new int[10] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
        for(int n = 0; n<ns.Length; n++)
        {
            for(int k = 0; k < ks.Length; k++)
            {
                for (int r = 0; r < rs.Length; r++)
                {
                    RunProg(ns[n], ks[k], rs[r]);
                }
            }
        }

where RunProg takes a relatively substantial amount of time. I would like to parallelize this code. What is the most straight forward way to parallelize this in C#?

I have not tried any method yet. I was trying to decide between the different functionalities available in C#

9
  • 1
    Is RunProg safe to call concurrently? we can't tell you the most straightforward way without knowing that information. Also, what have you tried so far to do it and what did not work about it? Commented Oct 23, 2017 at 15:36
  • 1
    Why is everyone marking this question as "too broad"? Doesn't make any sense whatsoever. Commented Oct 23, 2017 at 15:37
  • RunProg can safely be run concurrently yes. Commented Oct 23, 2017 at 15:38
  • @bdeonovic A simple way to parallelize this is to replace your loop(s) with a computed sequence of Tasks which run on the thread pool, and which you aggregate into a result using Task.WhenAll. Commented Oct 23, 2017 at 15:39
  • 2
    @AsadSaeeduddin, it's a typical "what have you tried" close reason. "I would like to parallelize this code" - and? What happen then? The world crashes or google starts saying 404? "I was trying to decide" - here comes your broad part. Commented Oct 23, 2017 at 15:40

3 Answers 3

2

A simple way to parallelize this is to produce a sequence representing all combinations of inputs, then transforming this sequence to a sequence of thread pool tasks representing the result. This final sequence can simply be passed to Task.WhenAll to await the completion of all tasks.

class Program
{
    static void Main(string[] args)
    {
        int[] ns = new int[4] { 100, 500, 1000, 5000 };
        int[] ks = new int[5] { 5, 10, 15, 80, 160 };
        int[] rs = new int[10] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

        var inputs = ns
            .SelectMany(n => ks.Select(k => new { n, k }))
            .SelectMany(x => rs.Select(r => new { x.n, x.k, r }));

        var tasks = inputs.Select(x => Task.Run(() => RunProg(x.n, x.k, x.r)));
        var results = Task.WhenAll(tasks).Result;
    }

    static int RunProg(int n, int k, int r)
    {
        Thread.Sleep(1000);
        return n + k + r;
    }
}

You can also Parallel.ForEach over the inputs collection, as mentioned in the other answers.

Parallel.ForEach(inputs, x => RunProg(x.n, x.k, x.r));
Sign up to request clarification or add additional context in comments.

6 Comments

Except if you have thousands items in your array - that will start thousands of threads and put whole process to the knees.
@Evk How many threads are started is dictated by the thread pool AFAIK, it is not unbounded.
Well that's true but still, usually you want to limit number of parallel computations in such cases.
@Evk It's already limited, the thread pool limits the number of computations. If you want custom control over concurrency you can pass a custom scheduler.
Default number of max threads in thread pool is very high (on last .NET versions at least), tens of thousands. So limitation comes only from the fact new threads are added with a delay (of something like 0.5 seconds as I remember). But that means you are starving global resource (thread pool), because any other code which uses thread pool will also wait for 0.5 seconds to start new thread while your code is running. That's of course assuming RunProg runs for quite a long time. All in all I'd prefer Parallel.ForEach.
|
2

There is a Parallel.For method:

int[] ns = new int[4] { 100, 500, 1000, 5000 };
int[] ks = new int[5] { 5, 10, 15, 80, 160 };
int[] rs = new int[10] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
Parallel.For(0, ns.Length, n =>
{
    Parallel.For(0, ks.Length, k =>
    {
        Parallel.For(0, rs.Length, r =>
        {
            RunProg(ns[n], ks[k], rs[r]);
        });
    });
});

This should work provided that the order in which the RunProg method is called is not important, and that the method itself is thread-safe.

3 Comments

Isn't it better to first produce list of all combinations in 3 arrays and then run Parallel.For over that (instead of 3 Parallel.For)?
The partitioning in this example will be wonky, you should use a single Parallel.For after constructing a single sequence of work inputs.
"Isn't it better...". Not if the order doesn't matter. First producing all combinations means that you will end up with more iterations in total. The code in my answer runs the RunProg method 4 *5 * 10 = 200 times as expected, once for each combination of n,k and r.
0

Use Parallel.For() for the loops: https://msdn.microsoft.com/de-de/library/dd460713(v=vs.110).aspx

This works if the iterations are not dependent on each other.

1 Comment

Why only inner loop? What if rs array contains just 1 element and ns and ` ks` contain thousand each?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.