Parallel.Foreach 循环中的第 3 方 SDK 调用处理事件

问题描述 投票:0回答:1

我正在批量处理项目并并行处理它们,如下所示。我需要通过下面显示的两个事件处理程序发送的任务中未返回的信息(状态更新)。这些可以在并行 foreach 循环中处理吗?我假设结果会按照目前的方式相互叠加?如何安全地更新 SQL 数据库表中的状态?

public function async task<junk> blahblahblah(List<items> unprocessedItems)
{          
    var tasks = new List<Task>();
    Parallel.ForEach(unprocessedItems,  item =>
    {
        var exporter = new Exporter();
        exporter.ExportEnded += Exporter_ExportEnded;
        exporter.StatisticsReceived += Exporter_StatisticsReceived;
        var exporterTask = exporter.ExportAsync(cameraConfig, PlaybackMode.Sequential, fileName, true);

        //do exporter task stuff
        tasks.Add(exporterTask);
    }

    await Task.WhenAll(tasks);
}
    
private void Exporter_StatisticsReceived(object sender, StatisticsEventArgs e)
{
    //do stuff with event information
    //update percent status in DB for each parallel row independently.
}
    
private void Exporter_ExportEnded(object sender, EndedEventArgs e)
{
    //do stuff with event information
    //log results in database.
}
c# service sdk task-parallel-library parallel.foreach
1个回答
0
投票

我正在批量处理项目并并行处理它们,如下所示。

Parallel.ForEach
的用法不正确。它从多个线程调用
List<T>.Add
,并且
Add
不是线程安全的方法。更广泛地说,它并行化对象构造,添加几个事件处理程序,启动导出(而不是导出本身),并将项目添加到列表中。并行化的工作总量几乎为零。

一次启动所有导出,然后异步等待它们全部完成会更惯用:

var tasks = unprocessedItems.Select(item =>
{
  var exporter = new Exporter();
  exporter.ExportEnded += Exporter_ExportEnded;
  exporter.StatisticsReceived += Exporter_StatisticsReceived;
  return exporter.ExportAsync(cameraConfig, PlaybackMode.Sequential, fileName, true);
}).ToList();

await Task.WhenAll(tasks);

我需要通过下面显示的两个事件处理程序发送的任务中未返回的信息(状态更新)。这些可以在并行 foreach 循环中处理吗?

我认为这没有道理。事件处理程序将已经进入线程池线程,多个事件同时发生。

如何安全地更新SQL数据库表中的状态?

与其他 SQL 更新的方式相同吗? SQL 数据库能够适应并发性。

您将需要处理竞争条件,例如在

StatisticsReceived
之后调用
ExportEnded
。正确设计的 SQL 语句应该能够处理这个问题。

© www.soinside.com 2019 - 2024. All rights reserved.