Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Return value and keyword inside a Parallel ForEach or For loop

What is the correct way to return a value from a Parallel ForEach or For loop?

For example is the following code correct/threadsafe?

{
    Process[] processes = Process.GetProcesses();
    String ProcessName = String.Empty;
    Parallel.ForEach(processes, curItem => {
        if (curItem.Handle == this._handle) {
            ProcessName = curItem.ProcessName;
            return;
        }
    });
    return ProcessName;
}

OR THIS?

{
    Process[] processes = Process.GetProcesses();
    List<String> ProcessNames = new List<String>();
    Parallel.ForEach(processes, curItem => {
            ProcessNames.Add(processes.ProcessName);
        }
    });
    return ProcessNames;
}

Lastly what is the behavior of the return keyword inside a Parallel For or ForEach loop?

IE: Does it immediately terminate all threads? Will it cause any artifacts that you might not expect?

Hopefully what I am asking makes sense.

PS: To be more specific. Looking at the first example is my modification of the String threadsafe and contain the value I expect because of the return statement? And in the second example is my modification of the List Collection threadsafe? Will all the values I expect be added?

like image 223
Maxim Gershkovich Avatar asked Mar 29 '11 14:03

Maxim Gershkovich


People also ask

Does ForEach work in parallel?

The main reason for using the foreach package is that it supports parallel execution, that is, it can execute those repeated operations on multiple processors/cores on your computer, or on multiple nodes of a cluster.

Is parallel ForEach faster than ForEach?

The execution of Parallel. Foreach is faster than normal ForEach.

How do you break a parallel ForEach?

It's not uncommon to break the execution of a for/foreach loop using the 'break' keyword. A for loop can look through a list of integers and if the loop body finds some matching value then the loop can be exited.


2 Answers

I'd use PLINQ here:

return Process
    .GetProcesses()
    .AsParallel()
    .SingleOrDefault(p => p.Handle == this._handle);

I wonder whether the amount of data you're handling here merits going parallel...

To answer your question more directly, in order to handle early exit from a parallel loop you should look into overloads that hand a ParallelLoopState to the executing delegate. This can be used to control early loop termination.

EDIT:

The errors you are seeing is because your process does not have sufficient privilege to access the handle of the processes you inspecting. A brute force way of handling this would be as follows:

Process
.GetProcesses()
//.AsParallel()
.Where(p=>{try{var h=p.Handle;}catch{return false;}return true;})
.SingleOrDefault(p => p.Handle == this._handle)

Of course, assuming this._handle refers to the handle of the currently executing process:

Process.GetCurrentProcess()

would surely be a better fit?

like image 62
spender Avatar answered Sep 28 '22 19:09

spender


return inside a parallel foreach loop is basically the same as a continue in a normal loop, because the return is inside the delegate that is executed for each item. This means, it doesn't terminate any threads and especially doesn't terminate execution of the parallel foreach loop.

like image 23
Daniel Hilgarth Avatar answered Sep 28 '22 19:09

Daniel Hilgarth