如何将进程方法多线程化

本文关键字:多线程 方法 进程 | 更新日期: 2023-09-27 18:16:38

我正在尝试使用多线程来更快地处理结果列表。我尝试使用并行的每一个,但当进程方法运行时,我没有收到正确的结果。

private IEnumerable<BulkProcessorResult> GetProccessResults(List<Foo> Foos)
{
    var listOfFooLists = CreateListOfFooLists(Foos);
    var bulkProcessorResults = new List<BulkProcessorResult>();
    Parallel.ForEach(listOfFooLists, FooList =>
    {
        foreach (var Foo in FooList)
        {
            var processClaimResult = _processor.Process(Foo);
            var bulkProcessorResult = new BulkProcessorResult()
            {
                ClaimStatusId = (int) processClaimResult.ClaimStatusEnum,
                Property1 = Foo.Property1
            };
            bulkProcessorResults.Add(bulkProcessorResult);
        }
    }); 
    return bulkProcessorResults;
}

如果我使用正常的forEach,我将得到正确的输出。如果我使用上面的代码,当应该有三个状态为1和一个状态为3时,我得到所有2的状态'。

我真的是一个新的线程,所以任何帮助将是伟大的

如何将进程方法多线程化

最明显的问题是您正在使用多个线程(好吧,这在调用Parallel.ForEach时有些隐藏,但您应该意识到它通过使用多个线程/任务实现并行性),但您正在使用List<T>,这不是线程安全的集合类:

一个List<T>可以支持多个reader并发,只要不修改集合。在集合中枚举本质上不是线程安全的过程。在枚举与一个或多个写访问竞争的罕见情况下,确保线程安全的唯一方法是在整个枚举期间锁定集合。要允许多个线程访问集合进行读写,您必须实现自己的同步

与其实现自己的同步,还不如不修改代码中的其他内容,我还是使用ConcurrentQueue<T>:

private IEnumerable<BulkProcessorResult> GetProccessResults(List<Foo> Foos)
{
    var listOfFooLists = CreateListOfFooLists(Foos);
    var bulkProcessorResults = new ConcurrentQueue<BulkProcessorResult>();
    Parallel.ForEach(listOfFooLists, FooList =>
    {
        foreach (var Foo in FooList)
        {
            var processClaimResult = _processor.Process(Foo);
            var bulkProcessorResult = new BulkProcessorResult()
            {
                ClaimStatusId = (int) processClaimResult.ClaimStatusEnum,
                Property1 = Foo.Property1
            };
            bulkProcessorResults.Enqueue(bulkProcessorResult);
        }
    }); 
    return bulkProcessorResults;
}

如何处理整个事情作为并行Linq查询?

private IEnumerable<BulkProcessorResult> GetProccessResults(List<Foo> Foos)
{
  var listOfFooLists = CreateListOfFooLists(Foos);
  return listOfFooLists.AsParallel()
                       .SelectMany(FooList => FooList)
                       .Select(Foo =>
                            new BulProcessorResult {
                               ClaimStatusId = (int)_processor.Process(Foo),
                               Property1 = Foo.Property1
                            }).ToList();
}