MVC5网站中的批处理

时间:2015-12-18 17:19:43

标签: c# .net asp.net-mvc task-parallel-library batch-processing

我有一个使用EF进行数据访问的MVC网站。该应用程序接收数据,运行一系列计算并存储结果。每批数据可以有几千条记录,计算平均需要30秒 - 我想在后台运行所有这些。

到目前为止,我已经安装了Hangfire以触发批次。然后我做了:

var queue = new Queue<MyItem>();

// queue is populated ...

while (queue.Any())
{
    var item = queue.Dequeue();
    var task = Task.Run(() =>
    {
        using (var context = new MyDbContext())
        {
            context.MyItem.Add(item);

            // Run Calculations

           try {
               context.SaveChanges();
           }
           catch {
               // Log error
           }
        }
    }
}

当批处理正在运行时,站点会变得完全没有响应,或者我收到“基础提供程序在打开时失败”错误。

有更好的方法吗?

1 个答案:

答案 0 :(得分:5)

您似乎正在使用Task.Run创建任务而不是等待它们完成。这意味着您将为队列中的每个项生成一个任务,该任务将在不同的ThreadPool个线程上并发运行。这可能是一种负担,可能(并且可能确实)影响您的常规请求。

您应该以某种方式限制这些任务的并发性。最简单的IMO使用的是TPL Dataflow的ActionBlock。您可以使用委托和选项(例如MaxDegreeOfParallelism)创建块,将项目发布到其中并等待它完成:

block = new ActionBlock<MyItem>(item =>
{
    using (var context = new MyDbContext())
    {
        context.MyItem.Add(item);

        // Run Calculations

       try {
           context.SaveChanges();
       }
       catch {
           // Log error
       }
    } 
}, new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 2 });

while (queue.Any())
{
    var item = queue.Dequeue();
    block.Post(item);
}

block.Complete();
await block.Completion;