Parallel.ForEach - Graceful Cancellation

前端 未结 1 725
北海茫月
北海茫月 2021-02-07 14:15

On the subject of waiting until tasks are complete and thread synchronisation.

I currently have an iteration i have enclosed within a Parallel.ForEach. In the Example be

相关标签:
1条回答
  • 2021-02-07 14:28

    I have mocked up some code below that may answer your question. The basic point is that you get fork/join parallelism with Parallel.ForEach, so you don't need to worry about race conditions outside of the parallel task (the calling thread blocks until the tasks have completed, successfully or otherwise). You just want to make sure to use the LoopState variable (the second argument to the lambda) to control your loop state.

    If any iteration of the loop threw an unhandled exception, the overall loop will raise the AggregateException caught at the end.

    Other links that mention this topic:

    Parallel.ForEach throws exception when processing extremely large sets of data

    http://msdn.microsoft.com/en-us/library/dd460720.aspx

    Does Parallel.ForEach limits the number of active threads?

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;
    using System.ServiceModel;
    
    namespace Temp
    {
        public class Class1
        {
            private class MockWcfProxy
            {
                internal object ProcessIntervalConfiguration(string item)
                {
                    return new Object();
                }
    
                public CommunicationState State { get; set; }
            }
    
            private void myFunction()
            {
    
                IList<string> iListOfItems = new List<string>();
                // populate iListOfItems
    
                CancellationTokenSource cts = new CancellationTokenSource();
    
                ParallelOptions po = new ParallelOptions();
                po.MaxDegreeOfParallelism = 20; // max threads
                po.CancellationToken = cts.Token;
    
                try
                {
                    var myWcfProxy = new MockWcfProxy();
    
                    if (Parallel.ForEach(iListOfItems, po, (item, loopState) =>
                        {
                            try
                            {
                                if (loopState.ShouldExitCurrentIteration || loopState.IsExceptional)
                                    loopState.Stop();
    
                                // long running blocking WS call, check before and after
                                var response = myWcfProxy.ProcessIntervalConfiguration(item);
    
                                if (loopState.ShouldExitCurrentIteration || loopState.IsExceptional)
                                    loopState.Stop();
    
                                // perform some local processing of the response object
                            }
                            catch (Exception ex)
                            {
                                // cannot continue game over.
                                if (myWcfProxy.State == CommunicationState.Faulted)
                                {
                                    loopState.Stop();
                                    throw;
                                }
    
                                // FYI you are swallowing all other exceptions here...
                            }
    
                            // else carry on..
                            // raise some events and other actions that could all risk an unhanded error.
                        }
                    ).IsCompleted)
                    {
                        RaiseAllItemsCompleteEvent();
                    }
                }
                catch (AggregateException aggEx)
                {
                    // This section will be entered if any of the loops threw an unhandled exception.  
                    // Because we re-threw the WCF exeption above, you can use aggEx.InnerExceptions here 
                    // to see those (if you want).
                }
                // Execution will not get to this point until all of the iterations have completed (or one 
                // has failed, and all that were running when that failure occurred complete).
            }
    
            private void RaiseAllItemsCompleteEvent()
            {
                // Everything completed...
            }
        }
    }
    
    0 讨论(0)
提交回复
热议问题