【问题标题】:High volume POST controller asp core 1.1大容量 POST 控制器 asp core 1.1
【发布时间】:2017-11-06 12:59:55
【问题描述】:

我需要一个 POST 控制器来处理大量流量 我做过类似的事情

    [HttpPost]
    public async Task<IActionResult> Post([FromBody] List<VdoPlayInfo> lv)
    {
        var seesionID = HttpContext.Session.GetString("sessionId");
        var vdoID = HttpContext.Session.GetInt32("videoid");
        var tasks = new Task[lv.Count];
        for (int i = 0; i < lv.Count; i++)
        {
            tasks[i] = Task.Run(() => _ADB.SaveLogView(lv[i]);                    
        }
        await Task.WhenAll(tasks);
        return Ok();          
    }

工作几秒钟后,我收到此错误

System.ArgumentOutOfRangeException: 'Index was out of range. 
Must be non-negative and less than the size of the collection.'

即使lv.Count = 2 很艰难,我的i 指数也达到了 5。 有什么问题?

【问题讨论】:

  • 您能重新表述一下您遇到的问题吗?
  • 这样更好吗?
  • here
  • @Kulpemovitz 你确定`_ADB.SaveLogView(lv[i])` 对你的列表没有任何作用吗?
  • BRAHIM Kamel - 什么都不做。我只是使用 Dapper 和 SP 将它推送到数据库

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


【解决方案1】:

目前尚不清楚您最终要在这里做什么,但如果您的目标是高性能,那么实现这一目标的方法绝对是错误的。 Task.Run 将在您每次调用它时从池中拉出一个新线程,因此列表中有两个项目,您的操作现在消耗三个线程(一个用于请求,一个用于每个列表项)。显然,随着列表项的扩展,您的线程使用量也会随之增加,因此您正在显着降低服务器的潜在吞吐量,并且实际上可能最终会出现线程匮乏。

尚不清楚_ADB.SaveLogView 在做什么,但如果它是同步工作,你需要意识到使用Task.Run 不会使其异步。同步仍然是同步的,你只是阻塞了一个不同的线程而不是请求线程。但是,由于您正在等待任务完成,因此请求线程仍然被阻塞,因此除了浪费一堆可能正在处理其他请求的线程之外,您实际上没有实现任何目标。

如果 _ADB.SaveLogView 是异步的(在这种情况下,您应该将其命名为 _ADB.SaveLogViewAsync 以避免混淆),那么您可以通过以下方式简化代码(并避免浪费线程):

var tasks = new Task[lv.Count];
for (int i = 0; i < lv.Count; i++)
{
    tasks[i] = _ADB.SaveLogViewAsync(lv[i]);                    
}

由于它应该已经在这种情况下返回Task,因此无需将其包装在另一个Task中。

但是,理想情况下,您实际上应该以事务方式处理此问题。如果保存其中一个实体出现问题,其他实体仍会被保存。如果您需要重新提交以保存失败的一个或多个实体,这可能会导致问题。同样,尚不清楚此方法在做什么,但使用 Entity Framework 之类的东西,您只需将每个新实体添加到 DbSet(将它们标记为在更改跟踪中创建),然后调用 SaveChangesAsync 即可一次,它会尝试一次性保存所有项目,包装在一个事务中,所以如果有任何失败,一切都会回滚。

如果您使用实体框架或其他支持底层事务的系统,您应该使用该功能。如果您正在执行某种手动数据库工作,那么您应该滚动您自己的事务。

【讨论】:

  • 谢谢你,克里斯 - 很棒的东西。 “SaveLogView”是一个使用 Dapper 和存储过程将数据存储到 SQL 服务器的简单函数。使存储过程异步只是在函数行中添加异步?
  • 没有。您可以通过调用异步方法使其异步。 Dapper 支持异步使用,因此您只需要以这种方式使用它。
【解决方案2】:

你能试试这个吗?

for (int i = 0; i < lv.Count; i++)
    {
        var item = lv[i];
        tasks[i] = Task.Run(() => _ADB.SaveLogView(item);                    
    }

【讨论】:

    猜你喜欢
    • 2018-10-27
    • 2017-11-12
    • 2019-12-31
    • 1970-01-01
    • 2022-07-27
    • 2021-03-12
    • 1970-01-01
    • 1970-01-01
    • 2017-09-02
    相关资源
    最近更新 更多