.net 多线程处理集合中具有特定顺序的项

9fkzdhlc  于 2023-10-21  发布在  .NET
关注(0)|答案(2)|浏览(150)

我有一个关于多线程的问题。也许这个问题很容易解决,但我不知道哪种方法是最好的!:)
我有一些元素的集合,例如List<SportEventSettings>
让我们假设这个集合有元素:

SportEventSettings_1;
SportEventSettings_2;
SportEventSettings_3;
SportEventSettings_4;
SportEventSettings_5;

我使用.NET的任务并行库中的Parallel.ForEach方法在不同的线程中处理这个集合并发送给客户。但在这种情况下,我们不能保证这些元素从集合将发送到客户在同一个订单后,在我们这边处理。我如何决定这一点,并将根据收集的顺序发送这些项目?
P.S.不重要!!!)在我们这边加工订货。但重要的发送列表中的项目在相同的顺序在列表中。

7eumitmz

7eumitmz1#

使用. AsParallel()AsOrdered()而不是Parallel.ForEach()。这允许并行处理项,并且仍然按照与它们在输入序列中出现的顺序相同的顺序枚举处理的项。

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);
}
oug3syen

oug3syen2#

如果你非常关心顺序,你可以使用像ConcurrentQueue<T>这样的东西,但是这是FIFO逻辑,所以你需要在删除项目时小心。
如果您正在寻找一个完全灵活的选项,还有BlockingCollection<T>,在这种情况下非常方便。Here是一篇很好的文章,this是原始的MS文档。
下面你可以看到一个尝试从列表中获取一个项目的案例:

BlockingCollection<MyClass> bCollection = new BlockingCollection<MyClass>(boundedCapacity: 2);
bCollection.Add(new MyClass{ Field1 = "Test" });
bCollection.Add(new MyClass{ Field1 = "Test2" };

var item = bCollection.Take();
item = bCollection.Take();

if (bCollection.TryTake(out item, TimeSpan.FromSeconds(1)))
{
    Console.WriteLine(item);
}
else
{
    Console.WriteLine("No item removed");
}

相关问题