拥有一份执行以下 2 项任务的工作
- 从数据库中读取最多 300 个唯一的
customerId
到列表
中。 - 然后为每个
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.ForEach
或await 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
}
FetchCustomer
和 SaveCustomer
可以使用 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));
}
我还建议您查看该博客中的这篇文章:
- StartNew is Dangerous
- Async and Await
- Don't Block on Async Code
- Async/Await - Best Practices in Asynchronous Programming
另一个选项是使用TPL Dataflow
扩展名,与此答案非常相似:
Nesting await in Parallel foreach
我建议您检查链接帖子的内容,并自行决定要实现哪种方法。
关于c# - 如何使用多线程为集合中的每个项目调用存储过程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35932203/