Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PLINQ delayed execution

Tags:

I'm trying to understand how parallelism might work using PLINQ, given delayed execution. Here is a simple example.

string[] words = { "believe", "receipt", "relief", "field" };
bool result = words.AsParallel().Any(w => w.Contains("ei"));

With LINQ, I would expect the execution to reach the "receipt" value and return true, without executing the query for rest of the values.

If we do this in parallel, the evaluation of "relief" may have began before the result of "receipt" has returned. But once the query knows that "receipt" will cause a true result, will the other threads yield immediately?

In my case, this is important because the "any" test may be very expensive, and I would want to free up the processors for execution of other tasks.

like image 487
tbischel Avatar asked Mar 08 '10 18:03

tbischel


People also ask

Is PLINQ faster?

In most cases, PLINQ performs much faster than its non-parallel counterpart LINQ. However, there is some performance overhead, which is related to partitioning and merging while parallelizing the LINQ.

Which extension method do you need to run a parallel query in PLINQ?

AsParallel extension method on the source sequence and executing the query by using the ParallelEnumerable. ForAll method. This documentation uses lambda expressions to define delegates in PLINQ. If you are not familiar with lambda expressions in C# or Visual Basic, see Lambda Expressions in PLINQ and TPL.

What is AsParallel in Linq C#?

AsParallel(IEnumerable)Enables parallelization of a query. public: [System::Runtime::CompilerServices::Extension] static System::Linq::ParallelQuery ^ AsParallel(System::Collections::IEnumerable ^ source); C# Copy.


1 Answers

Unfortunately, the other threads will not "yield" immediately.

As soon as Any() finds a valid element, the PLINQ scheduler will stop scheduling new threads to check for new elements. Any existing partitioners will also receive a cancellation request, which will prevent those partitions from calling Any() on another item.

However, any threads that are currently executing the lambda expression within your Any() method will still be executing, as there's no way for them to know that another thread has succeeded. It will prevent new threads from calling into Any(), but not cancel all of the ones in a "very expensive" delegate.

On a side note:

PLINQ, unlike LINQ to Objects, doesn't really use deferred execution. When you call AsParallel() on an IEnumerable<T>, the ParallelQuery<T> that is generated will actually start processing your routine in parallel. Deferred execution would dramatically reduce the effectiveness of PLINQ, since it would be impossible to schedule, in parallel, without creating the work partitioners and scheduling in advance.


Edit:

After thinking about this - if your lambda is VERY expensive, you might want to consider using a CancellationToken. I blogged, in detail, about how cancellation in PLINQ works. Typically, you'd just use a token and call ThrowIfCancellationRequested() - however, you can also use a CancellationToken and check IsCancellationRequested, which would let you make your lambda "exit early", providing you a way to stop the background processing sooner...

like image 92
Reed Copsey Avatar answered Oct 11 '22 13:10

Reed Copsey