Question

I am again struggling to understand some things for parallel computation. In the code I am working on, I have a class that extends list<list<double>>. Inside this class, I'm writing a method to return the average of the values in the list<list<double>>. This method is private.

public class myClass : list<list<double>>
{
    //properties and stuff
    private double average()
    {
        //method body
    }
}

I two versions for this method, both of them working. The first version is serial:

private double average()
{
    double avg = 0;
    for (int i = 0; i < this.Count; i++)
    {
        for (int j = 0; j < this[0].Count; j++)
        {
            avg += this[i][j];
        }
    }
    avg = avg / (this.Count*this[0].Count);
    return avg;
}

The second version is parallel:

private double average()
{
    double avg = 0;
    double[] cumsum = new double[this.Count];
    Parallel.For(0, this.Count, i =>
        {
            cumsum[i] = 0;
            for (int j = 0; j < this[0].Count; j++)
            {
                cumsum[i] += this[i][j];
            }
        });
    avg = cumsum.Sum() / ((this.Count * this[0].Count));
    return avg;
}

As a learning exercise, I tried to mess things up by using more complex parallel threading. My idea was to make do without the intermediate array in which I sum the lines. Specifically, this was my attempt (doesn't work):

private double average()
{
    double avg = 0;
    Parallel.For<double>(0, this.Count, () => 0, (i, loop, sub) =>
        {
            for (int j = 0; j < this[0].Count; j++)
            {
                sub += this[i][j];
            }
            return sub;
        },
        (x) => 
            {
                double tot = avg;
                Interlocked.CompareExchange(ref avg, tot+sub, tot);
            });
    return avg / ((this.Count * this[0].Count));
}

This snippet has (at least) two mistakes. The first error it give me is on the sub += this[i][j];:

The best overloaded method match for 'System.Collections.Generic.List>.this[int]' has some invalid arguments

I do not understand this error here, because both i and j are of type int.

Then I have a further error on Interlocked.CompareExchange(ref avg, tot+sub, tot); (expected, because I don't really understand how this method works):

The name 'sub' does not exist in the current context

Can someone point me to a correct form of the last snippet? And/or some material to clarify this things? I read from http://msdn.microsoft.com/en-us/library/dd460703.aspx but it didn't help make things clear for me.

Was it helpful?

Solution

Personally, I would use:

double sum = yourListOfList.AsParallel().SelectMany(list => list).Average();

In order to fix your method, you need to property use your loop state in the local final lambda. (You're not using x at all currently.)

double sum = 0;
var syncObj = new object();
Parallel.For<double>(0, this.Count, () => 0, (i, loop, sub) =>
    {
        var innerList = this[i];
        for (int j = 0; j < innerList.Count; j++)
        {
            sub += innerList[j];
        }
        return sub;
    },
    (x) => 
        {
            lock(syncObj)
               sum += x;
        });
return sum / ((this.Count * this[0].Count));

Note that your version (and my "correction") has many drawbacks. It's assuming that each sub list is the same length as this[0], which is not guaranteed or suggested by the types.

OTHER TIPS

The first error is caused because the i argument is of the long type. This is because two similar overloads exist, one with the first parameter of the int type, another with the long type. To select the "int" overload, you have to instantiate a lambda expression explicitly:

new Func<int, ParallelLoopState, double, double>((i, loop, sub) => { ... })


The second error is caused because the sub variable doesn't exist in the given scope.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top