ASP.NET MVC 5如何在C#异步中进行快速处理

camsedfj  于 2022-12-05  发布在  .NET
关注(0)|答案(3)|浏览(163)

我怎样才能以最快的方式运行上面的代码。什么是最好的做法?

public ActionResult ExampleAction()
        {
            // 200K items
            var results = dbContext.Results.ToList();

            foreach (var result in results)
            {
                // 10 - 40 items
                result.Kazanim = JsonConvert.SerializeObject(
                    dbContext.SubTables // 2,5M items
                    .Where(x => x.FooId == result.FooId)
                    .Select(select => new
                    {
                        BarId = select.BarId,
                        State = select.State,
                    }).ToList());

                dbContext.Entry(result).State = EntityState.Modified;
                dbContext.SaveChanges();
            }

            return Json(true, JsonRequestBehavior.AllowGet);
        }

这个过程平均需要500毫秒作为同步。我有大约2M条记录。这个过程完成了200K次。
我应该如何进行异步编码?
我怎样才能用异步方法更快更容易地做到这一点呢?

yhived7q

yhived7q1#

以下两个建议可以将性能提高几个数量级:
1.分批工作:
1.使客户端发送一页数据进行处理;及/或
1.在Web服务器代码中,将项添加到队列中并分别处理它们。
1.使用SQL代替EF:
1.编写高效的SQL;及/或
1.使用存储过程在数据库内部执行工作,而不是在数据库和代码之间移动数据。

ukdjmx9f

ukdjmx9f2#

对于异步代码,您无法做任何事情来提高它的性能,但是有一些事情可以使它更快。
如果在循环中调用dbContext.SaveChanges(),EF会将每个实体的更改作为一个单独的事务写回到数据库中。将dbContext.SaveChanges()移到循环之后。这样EF会在一个事务中一次性写回所有更改。
总是尽可能少地调用.SaveChanges()。一次调用50次更改比50次调用每次更改1次更好、更快、更有效。

tvmytwxo

tvmytwxo3#

和欢迎。
在异步性方面,我认为有很多不正确的地方,但我想只有当有并发用户调用服务器时才有关系。这与可伸缩性和负责启动线程以处理传入HTTP请求的线程池有关。
你可以看到,如果你占用一个线程池线程很长一段时间,该线程将不会对进入的HTTP请求出列做出贡献。这几乎使你处于一个位置,你可以旋转起来,最多每秒约2个新的线程池线程。如果你的进入HTTP请求速率比池产生线程的能力快,你所有的HTTP请求将开始看到增加的响应时间(缓慢)。
因此,一般来说,在执行I/O密集型工作时,总是使用async。大多数(或全部)物化方法都有异步版本,如.ToList()ToListAsync()CountAsync()AnyAsync()等。还有一个SaveChangesAsync()。我首先要做的是在正常情况下使用这些。你的似乎不是,所以我提到这只是为了完整。
我认为您至少必须在线程池之外运行这个繁重的进程。将Task.Factory.StartNew()TaskCreationOptions.LongRunning一起使用,但要运行synchronous代码,这样您就不会陷入白白等待返回任务的陷阱。
现在,所有这些只是为了得到一个“合适的” backbone 。我们还没有真正讨论如何让这个运行得更快。让我们这样做吧。
就我个人而言,我认为您需要在不同的方法之间进行一些基准测试。看起来您已经对这段代码进行了基准测试。现在听一下@tymtam,看看是否有一个存储过程版本运行得更快。我的预感,就像@tymtam的预感一样,肯定会更快。
如果你坚持用C#运行这个,我会并行化这个工作。这个的问题是实体框架。和往常一样,我的非常流行,但不友好的ORM,给了我们一个很大的但是EF的DB上下文使用单个连接,不允许多个同时查询。所以你不能用EF并行化这个。然后我会转移到我的好,使用Dapper,您可以将工作负载划分为多个线程,每个线程将执行独立的DB连接,并通过该连接处理您在开始时获得的200 K结果集的一部分。

相关问题