简体   繁体   English

通过许多异步调用在WebAPI中使用异步

[英]the use of async in WebAPI with many async calls

Sorry for the beginers question, I read a lot of post here and on the web and there is something fondemental I can't understand. 抱歉,对于初学者的问题,我在这里和网络上阅读了很多文章,有些东西我无法理解。

As I understood, the usage of async actions in WebAPI is mainly for scalability reasons, so any incoming request will be diverted to a worker instead to a thread and by that, more requests could be served. 据我了解,WebAPI中异步操作的使用主要是出于可伸缩性原因,因此任何传入的请求都将被转移到工作程序而不是线程上,从而可以处理更多请求。

My project consists on several huge actions that read/insert/update from DB by EF6 many times. 我的项目由EF6多次多次从DB读取/插入/更新的巨大动作组成。 the action looks like that: 动作看起来像这样:

    public async Task<HttpResponseMessage> Get(int id)
    {
     PolicyModel response = await policyRepository.GetPolicyAsync(id);
     return Request.CreateResponse<PolicyModel>(HttpStatusCode.OK,response);
    }

and GetPolicyAsync(int id) looks like that: 和GetPolicyAsync(int id)看起来像这样:

    public async Task<PolicyModel> GetPolicyAsync(int id)
    {
      PolicyModel response = new PolicyModel();
      User currentUser = await Repositories.User.GetUserDetailsAsync(id);

      if(currentUser.IsNew)
      {
         IEnumerable<Delivery> deliveries = await Repositories.Delivery.GetAvailableDeliveries();
         if(deliveries == null || deliveries.Count() == 0
         {
           throw new Exception("no deliveries available");
         }
         response.Deliveries = deliveries;
         Ienumerable<Line> lines = await Repositores.Delivery.GetActiveLinesAsync();
         lines.AsParallel().ForAll(line => {
         await Repositories.Delivery.AssignLineAsync(line,currentUser);
    }
    ...
      return response;   
    }

I didn't write the entire code but it goes quite a bit and it is also broken into several methods but that is the spirit of it 我没有编写完整的代码,但是它花了很多时间,并且也分为几种方法,但这就是它的精神。

now the question i have is: is it a good practice to use so many awaiters in one method? 现在我的问题是:以一种方法使用这么多等候者是一种好习惯吗? I saw that it is more difficult to debug, is it hard to maintain the thread context and for the sake of worker assignment, shouldn't I just use Task.Factory.StartNew() or maybe call a simple Task.Delay() so that the request will immidiatelly be diverted to a worker? 我看到调试起来更加困难,是否难以维护线程上下文以及为了进行工作人员分配,我不应该只使用Task.Factory.StartNew()还是应该调用简单的Task.Delay()这样该请求将立即转移给工人? I know that it is not a good practice (async all the way) so maybe just one async method at the end/begining of the GetpolicyAsync(int id) method 我知道这不是一个好习惯(一直都是异步的),因此在GetpolicyAsync(int id)方法的结尾/ GetpolicyAsync(int id)可能只是一个异步方法

EDIT: 编辑:

as I understood the mechanics of the async methods in .net, for every async method, the compiler is looking for a free thread and let it deal withthe method, the thread is looking for a free worker and assign the method to it and then report back to the compiler that it is free. 据我了解.net中异步方法的机制,对于每个异步方法,编译器都在寻找一个空闲线程并让它处理该方法,线程正在寻找一个空闲工人并为其分配方法,然后报告回到编译器,它是免费的。 so if we have 10 threads and for every thread there are 10 workers, the program can deals with 100 concurrent async methods. 因此,如果我们有10个线程,并且每个线程有10个工作程序,则该程序可以处理100个并发异步方法。 so back to web developement, the IIS assign x thread to each app pool, 10 for instance. 回到Web开发,IIS将x线程分配给每个应用程序池,例如10个。 that means that the async WebAPI method can handle 100 requests but if there is another async method inside, the amount of requests that can be dealth with are 50 and so on, am I right? 这意味着异步WebAPI方法可以处理100个请求,但是如果内部还有另一个异步方法,则可以处理的请求数量为50个,依此类推,对吗? and as I understood, I must call an async method in order to make the WebAPI method truely async and now, since it is a bad practice to use Task.Factory.StartNew() , I must at least use Task.Delay() 并且据我所知,我必须调用一个异步方法才能使WebAPI方法真正异步,现在,由于使用Task.Factory.StartNew()是一种不好的做法,因此我至少必须使用Task.Delay()

what I really want to gain is the scalability of the async WebAPI methods and the context awareness of synced methods 我真正想要获得的是异步WebAPI方法的可伸缩性和同步方法的上下文意识

in all the examples I've seen so far, they only show a very simple code but in real life, methods are far more complex 到目前为止,在所有示例中,它们仅显示了非常简单的代码,但在现实生活中,方法要复杂得多

Thanks 谢谢

There's nothing wrong with having many await s in a single method. 在一个方法中有很多await并没有错。 If the method becomes too complicated for you you can split it up into several methods: 如果该方法对您来说太复杂了,您可以将其分为几种方法:

public async Task<PolicyModel> GetPolicyAsync(int id)
{
    PolicyModel response = new PolicyModel();
    User currentUser = await Repositories.User.GetUserDetailsAsync(id);

    if(currentUser.IsNew)
    {
        await HandleDeliveriesAsync(await Repositories.Delivery.GetAvailableDeliveries());
    }
    ...
    return response;   
}

public async Task HandleDeliveriesAsync(IEnumerable<Delivery> deliveries)
{
    if(deliveries == null || deliveries.Count() == 0
    {
        throw new Exception("no deliveries available");
    }
    response.Deliveries = deliveries;
    Ienumerable<Line> lines = await Repositores.Delivery.GetActiveLinesAsync();
    lines.AsParallel().ForAll(line => {
    await Repositories.Delivery.AssignLineAsync(line,currentUser);   
}

Don't use Task.Factory.StartNew or Task.Delay as it just offloads the same work to a different thread. 不要使用Task.Factory.StartNewTask.Delay因为它只是将相同的工作卸载到了另一个线程上。 It doesn't add any value in most cases and actually harms in ASP.Net. 在大多数情况下,它不会增加任何价值,并且实际上会损害ASP.Net。

After much search, I came across this artical: https://msdn.microsoft.com/en-us/magazine/dn802603.aspx 经过大量搜索,我发现了以下文章: https : //msdn.microsoft.com/zh-cn/magazine/dn802603.aspx

it explains what @i3arnon said in the comment. 它解释了@ i3arnon在评论中所说的内容。 there are no workers at all, the threads are doing all the work. 根本没有工人,线程正在完成所有工作。
In a nutshell, the thread that handles a web request reach to an opporation that is designed to be done asyncronically on the driver stack, it creates a request and pass it to the driver. 简而言之,处理Web请求的线程到达了设计为在驱动程序堆栈上异步完成的工作,它创建了一个请求并将其传递给驱动程序。
The driver mark it as pending and reports "done" to the thread which goes back to the thread pool to get another assignment. 驱动程序将其标记为未决,并向线程报告“完成”,该线程返回线程池以获取另一个分配。
The actual job is not being done by threads but by the driver that borrowing cpu time from all threads and leave them free to attend to their businesses. 实际的工作不是由线程来完成,而是由驱动程序来完成,该驱动程序从所有线程中借用了CPU时间,并让他们有空去参加他们的业务。
When the opporation is done, the driver notifies it and an available thread comes to continue... 操作完成后,驱动程序会通知它,然后可用线程继续运行...

so, from that I learn that I should look into each and every async method and check that it actually does an opporation that uses the drivers asyncronically. 因此,据我了解,我应该研究每种异步方法,并检查其是否确实在使用异步驱动程序。

Point to think: the scallability of your website is dependent on the amount of opporations that are truly being done asyncronically, if you don't have any of them, then your website won't scale. 值得思考的是:网站的可调用性取决于真正异步进行的处理的数量,如果您没有这些处理的内容,那么您的网站将无法扩展。

moderators, I'm a real newbe, if I got it all wrong, please correct me Thanks! 主持人,我是一个真正的新手,如果我弄错了,请指正我,谢谢!

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

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