Search code examples
c#.netmultithreadingparallel-processingtask-parallel-library

Multi-threaded processing items from collection with specific ordering


I have a question about multithreading. Maybe the question is easily solved but I don't know which way is the best! :)

I have some collection of elements, for example, List<SportEventSettings>.

Let's imagine this collection has elements:

SportEventSettings_1;
SportEventSettings_2;
SportEventSettings_3;
SportEventSettings_4;
SportEventSettings_5;

I use Parallel.ForEach method from the Task Parallel Library of .NET for processing this collection in different threads and sending to customer. But in this case we can't promise that these elements from the collection will be send to customer in the same ordering after processing in our side. How can I decide this and will send this items according ordering in collection?

P.S. not important(!!!) processing ordering in our side. But important send list items in the same order as at list.


Solution

  • Use .AsParallel().AsOrdered() instead of Parallel.ForEach(). This allows to process items in parallel and still enumerate processed items in the same order as they appear in input sequence.

    var inputItems = new List<int>(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 });//List<int> is just example, input sequence can be any IEnumerable<T>
    
    var processedItems = inputItems
        .AsParallel()//Allow parallel processing of items
        .AsOrdered()//Force items in output enumeration to be in the same order as in input
        .WithMergeOptions(ParallelMergeOptions.NotBuffered)//Allows enumeration of processed items as soon as possible (before all items are processed) at the cost of slightly lower performace
        .Select(item =>
            {
                //Do some processing of item
                Console.WriteLine("Processing item " + item);
    
                return item;//return either input item itself, or processed item (e.g. item.ToString())
            });
    
    //You can use processed enumeration just like any other enumeration (send it to the customer, enumerate it yourself using foreach, etc.), items will be in the same order as in input enumeration.
    foreach (var processedItem in processedItems)
    {
        //Do whatever you want with processed item
        Console.WriteLine("Enumerating item " + processedItem);
    }