简体   繁体   English

EF核心查询循环异步

[英]EF core query loop asynchronous

In the previous day I am looking for a way to make my code fully asynchronous.在前一天,我正在寻找一种使我的代码完全异步的方法。 So that when called by a rest API, I' ll get an immediate response meanwhile the process is running in the background.这样,当被其他 API 调用时,我会在进程在后台运行的同时立即得到响应。

To do that I simply used tasks.Add(Task<bool>.Run( () => WholeProcessFunc(parameter) )) where WholeProcessFunc is the function that make all the calculations(it may be computationally intensive).为此,我简单地使用tasks.Add(Task<bool>.Run( () => WholeProcessFunc(parameter) ))其中WholeProcessFunc是进行所有计算的函数(它可能是计算密集型的)。 It works as expected however I read that it is not optimal to wrap the whole process in a Task.Run .它按预期工作,但是我读到将整个过程包装在Task.Run中并不是最佳选择。

My code need to compute different entity framework query which result depends on the previous one and contains also foreach loop.我的代码需要计算不同的实体框架查询,其结果取决于前一个,并且还包含foreach循环。 For instance I can' t understand which is the best practice to make async a function like this:例如,我不明白哪个是使async成为这样的函数的最佳实践:

public async Task<List<float>> func()
{
    List<float> acsi = new List<float>();

    using (var db = new EFContext())
    {
        long[] ids = await db.table1.Join(db.table2 /*,...*/)
            .Where(/*...*/)
            .Select(/*...*/).ToArrayAsync();

        foreach (long id in ids)
        {
            var all = db.table1.Join(/*...*/)
                .Where(/*...*/);
            float acsi_temp = await all.OrderByDescending(/*...*/)
                .Select(/*...*/).FirstAsync();
            if (acsi_temp < 0) { break; }

            acsi.Add(acsi_temp);
        }
    }
    return acsi;
}

In particular I have difficulties with the foreach loop and the fact that the result of a query is used in the next .特别是我对foreach循环和查询结果在 next 中使用的事实有困难。 Finally with the break statement which I don't get how to translate it.最后是我不知道如何翻译的 break 语句。 I read about cancellation token, could it be the way ?我读到了取消令牌,可能是这样吗?

Is wrapping up all this function in a Task.Run a solid solution ?是否将所有这些功能都包含在Task.Run中是一个可靠的解决方案?

In the previous day I am looking for a way to make my code fully asynchronous.在前一天,我正在寻找一种使我的代码完全异步的方法。 So that when called by a rest api, I' ll get an immediate response meanwhile the process is running in the background.这样,当被休息 api 调用时,我会在进程在后台运行的同时立即得到响应。

Well, that's one meaning of the word "asynchronous".嗯,这就是“异步”这个词的一种含义。 Unfortunately, it's completely different than the kind of "asynchronous" that async / await does .不幸的是,它async / await所做的那种“异步”完全不同 async yields to the thread pool, not the client (browser). async产生于线程池,而不是客户端(浏览器)。

It works as expected however I read that it is not optimal to wrap the whole process in a Task.Run.它按预期工作,但是我读到将整个过程包装在 Task.Run 中并不是最佳选择。

It only seems to work as expected.似乎只按预期工作。 It's likely that once your web site gets higher load, it will start to fail.一旦您的网站负载更高,它很可能会开始失败。 It's definite that once your web site gets busier and you do things like rolling upgrades, it will start to fail.可以肯定的是,一旦您的网站变得繁忙并且您进行滚动升级之类的操作,它就会开始失败。

Is wrapping up all this function in a Task.Run a solid solution ?是否将所有这些功能都包含在 Task.Run 中是一个可靠的解决方案?

Not at all.一点也不。 Fire-and-forget is inherently dangerous.即发即弃本质上是危险的。

A proper solution should be a basic distributed architecture :一个合适的解决方案应该是一个基本的分布式架构

  • A durable queue, such as an Azure Queue or Rabbit (if properly configured to be durable).持久队列,例如 Azure 队列或 Rabbit(如果正确配置为持久)。
  • An independent processor, such as an Azure Function or Win32 Service.独立处理器,例如 Azure 函数或 Win32 服务。

Then the ASP.NET app will encode the work to be done into a queue message, enqueue that to the durable queue, and then return.然后 ASP.NET 应用程序会将要完成的工作编码为队列消息,将其排入持久队列,然后返回。 Some time later, the processor will retrieve the message from that queue and do the actual work.一段时间后,处理器将从该队列中检索消息并执行实际工作。

You can translate your code to return an IAsyncEnumerable<...> , that way the caller can process the results as they are obtained.您可以翻译您的代码以返回一个IAsyncEnumerable<...> ,这样调用者就可以在获得结果时对其进行处理。 In an asp.net 5 MVC endpoint, this includes writing serialised json to the browser;在 asp.net 5 MVC 端点中,这包括将序列化的 json 写入浏览器;

public async IAsyncEnumerable<float> func()
{
    using (var db = new EFContext())
    {
        //...

        foreach (long id in ids)
        {
            //...
            if(acsi_temp<0) { yield break; }

            yield return acsi_temp;
        }
    }
}

public async Task<IActionResult> ControllerAction(){
    if (...)
        return NotFound();
    return Ok(func());
}

Note that if your endpoint is an async IAsyncEnumerable coroutine.请注意,如果您的端点是async IAsyncEnumerable协程。 In asp.net 5, your headers would be flushed before your action even started.在 asp.net 5 中,您的标题将在您的操作开始之前被刷新。 Giving you no way to return any http error codes.让您无法返回任何 http 错误代码。

Though for performance, you should try rework your queries so you can fetch all the data up front.虽然为了性能,您应该尝试重新处理查询,以便您可以预先获取所有数据。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM