c# - 如何使用多线程为集合中的每个项目调用存储过程

标签 c# asp.net sql-server xml multithreading

拥有一份执行以下 2 项任务的工作

  1. 从数据库中读取最多 300 个唯一的 customerId列表中。
  2. 然后为每个 customerId 调用一个存储过程,该过程在 SP 中执行查询、创建 XML(最多 10 KB)并将 XML 存储到数据库表中。

因此,在本例中表中应有 300 条记录。

平均而言,SP 需要大约 3 秒的时间来处理每个客户,直到创建 xml。这意味着,完成处理所有 300 位客户总共需要 15 分钟。问题是,将来可能会更加耗时。

我不想通过在应用程序中创建 xml 逻辑来使用批量插入选项。使用批量插入,如果 xml 创建失败,我将无法知道哪个 customerId 的数据有问题。所以我想给每个客户的 SP 打电话。

为了并行处理所有客户,我创建了 4 个专用线程,每个线程处理一组唯一的 customerId,所有 4 个线程一起在 5 分钟内处理了所有 300 个客户。这是我所期待的。

但是我想使用ThreadPool而不是创建自己的线程。

我想在这里有两种类型的线程。一种是为每个客户处理并创建 xml,另一种是针对已经创建的 XML 来处理客户。另一个线程将调用 SP,该 SP 将根据客户的可用 XML 更新客户表上的标志。

那么,并行快速处理 300 个客户并并行或在单独线程上更新客户表的最佳方式是什么?

这里专用线程仍然是不错的选择还是Parallel.ForEachawait Task.WhenAll

我知道Parallel.Foreach会阻塞主线程,我想用它来更新客户表。

最佳答案

您必须在多个实现选项中进行选择。首先,选择您正在使用的架构。您可以在 co-routine fashion 中实现您的算法,每当线程需要一些长时间准备的数据时,它就会通过 await 构造产生执行。

// It can be run inside the `async void` event handler from your UI.
// As it is async, the UI thread wouldn't be blocked
async Task SaveAll()
{
    for(int i = 0; i < 100; ++i)
    {
         // somehow get a started task for saving the (i) customer on this thread
        await SaveAsync(i);
    }
}

// This method is our first coroutine, which firstly starts fetching the data
// and after that saves the result in database
async Task SaveAsync(int customerId)
{
    // at this point we yield the work to some other method to be run
    // as at this moment we do not do anything
    var customerData = await FetchCustomer(customerId);
    // at this moment we start to saving the data asynchroniously
    // and yield the execution another time
    var result = await SaveCustomer(customerData);
    // at this line we can update the UI with result
}

FetchCustomerSaveCustomer 可以使用 TPL(它们可以用匿名方法替换,但我不喜欢这种方法)。 Task.Run将执行默认线程池中的代码,因此 UI 线程不会被阻塞 ( more about this method in Stephen Cleary's blog ):

async Task<CustomerData> FetchCustomer(int customerId)
{
    await Task.Run(() => DataRepository.GetCustomerById(customerId));
}

// ? here is a placeholder for your result type
async Task<?> SaveCustomer(CustomerData customer)
{
    await Task.Run(() => DataRepository.SaveCustomer(customer));
}

我还建议您查看该博客中的这篇文章:

另一个选项是使用TPL Dataflow扩展名,与此答案非常相似:

Nesting await in Parallel foreach

我建议您检查链接帖子的内容,并自行决定要实现哪种方法。

关于c# - 如何使用多线程为集合中的每个项目调用存储过程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35932203/

相关文章:

c# - 如何在 C# 中进行参数化 SELECT 查询?

c# - 用户定义的非法异常

c# - XElement 的 Linq to xml 部分

c# - 本地编译时如何将NuGet安装到.nuget文件夹中

c# - 为什么在 EF7 中使用谓词参数时不能使用 ToListAsync()?

sql - 使用过滤器 WHERE Field IN (<empty set>) 时从大表中删除花费的时间太长

c# - 如何使用 asp.net webform 处理 AngularJs?

asp.net - ASP.NET 中的 MembershipProvider

c# - 确定是否启用了 ELMAH?

mysql - SQL 连接和选择