简体   繁体   English

如何使用异步和等待,以便它将创建一个不同的任务或每个请求

[英]how to use async and await so that it will create a different task or each request

I am new in asp.net core and in asynchronous programming. 我是asp.net核心和异步编程的新手。 below is my code 下面是我的代码

protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
    var work = await TaskQueue.DequeueAsync(stoppingToken);
    while (!stoppingToken.IsCancellationRequested)
    {
        redirect(work);
    }
}

public async Task redirect(Func<CancellationToken, Task> work)
{
    await work();
}

So here when i run program and debug it cursor first go in ExecuteAsync method and from while loop it goes in redirect method. 所以在这里,当我运行程序并调试它时,光标首先进入ExecuteAsync方法,而从while循环进入重定向方法。 redirect method is asynchronous still it will wait on work method. 重定向方法仍然是异步的,它将等待工作方法。 so i think that it is not running asynchronous. 所以我认为它不是异步运行的。

i expect that when cursor go in work method it will start a new task(Thread). 我希望当光标进入工作方法时,它将启动一个新任务(线程)。

when i run program and debug it 当我运行程序并对其进行调试时

The behavior you're observing is Visual Studio trying to be helpful. 您正在观察的行为是Visual Studio 试图提供帮助。 It has special code to handle asynchronous methods, so that when you say "step to the next line", it won't suddenly transfer to some completely unrelated method; 它具有处理异步方法的特殊代码,因此,当您说“进入下一行”时,它不会突然转移到某些完全不相关的方法。 it will step to the next line in that method . 它将转到该方法的下一行。

i expect that when cursor go in work method it will start a new task(Thread). 我希望当光标进入工作方法时,它将启动一个新任务(线程)。

Tasks are not threads. 任务不是线程。 In particular, tasks created by async methods do not run on threads; 特别是, async方法创建的任务不会在线程上运行; they are just state objects that can notify other code when the async method has completed. 它们只是状态对象,可以在async方法完成时通知其他代码。

I recommend reading my async intro , and follow it up with async best practices . 我建议阅读我的async介绍 ,并通过async最佳实践进行跟进。

There are couple of misunderstanding in the way you have trying to use Async-Await , there is enough content on web, following are the specific details: 您尝试使用Async-Await的方式存在一些误解,网络上有足够的内容,以下是详细信息:

So here when i run program and debug it cursor first go in ExecuteAsync method and from while loop it goes in redirect method. 所以在这里,当我运行程序并调试它时,光标首先进入ExecuteAsync方法,而从while循环进入重定向方法。 redirect method is asynchronous still it will wait on work method. 重定向方法仍然是异步的,它将等待工作方法。 so i think that it is not running asynchronous 所以我认为它不是异步运行的

What await does is release the calling context, while the processing goes in the background, which helps system remains responsive, thus system has scalability / thread pool to cater to further requests, so only thing await doesn't do is block the calling thread / context, in debugger as seen in your code it will wait to finish. await所做的是释放调用上下文,而处理在后台进行,这有助于系统保持响应状态,因此系统具有可伸缩性/线程池来满足进一步的请求,因此, await唯一不做的事情就是阻塞调用线程/上下文中,在代码中看到的调试器中,它将等待完成。

Now what kind of processing does work do is it IO or Compute 现在,什么类型的处理work是IO还是Compute

If it's IO , that's where Async processing on a server is genuinely used, since thread pool thread is released and if used along with ConfigureAwait(false) it needn't re enter same context to process the response, which is expected by libraries. 如果是IO ,那就是真正在服务器上使用异步处理的地方,因为线程池线程已释放,并且如果与ConfigureAwait(false)一起使用,则不需要重新输入相同的上下文来处理响应,这是库期望的。 If it's compute, then it works well for a UI like WPF, since Ui thread remains responsive, but still processing takes away threads from current pool and that has limited / scarce availability. 如果是计算的,那么它就可以像WPF这样的UI很好地工作,因为Ui线程保持了响应能力,但是处理仍然从当前池中夺走了线程,并且可用性有限/稀缺。

Regarding your code 关于你的代码

  • In current form its a blocking code, since in the while loop you are calling redirect(work) , which in turn does await work , it release the caller, but awaiting it to complete before next Async operation can be executed 在当前形式下,它是一个阻塞代码,因为在while循环中,您正在调用redirect(work) ,而后者又确实await work ,它释放了调用者,但等待它完成才能执行下一个Async操作
  • Ideal way is to collect all tasks in a collection like List<Task> and when await the Task.WhenAll , that's when all aggregated tasks go together, while you asynchronously wait at the single representative Task for all of them to complete, that would still not a blcoking / call as in current code, but blocking for complete aggregated List, it is specified by @TheGeneral in the comments, thus helps in better processing since all tasks go together 理想的方式是将所有任务收集在List<Task>类的集合中,并在等待Task.WhenAll时将所有聚合的任务放在一起,而当您异步等待单个代表性Task使其完成时,仍然可以不是像当前代码中那样大胆地调用,而是阻止完整的聚合列表,它由@TheGeneral在注释中指定,因此有助于更好地处理,因为所有任务都一起执行
  • Also await work() is not correct, compilation error, this needs a Cancellation Token as I/p Parameter 另外await work()不正确,编译错误,这需要一个取消令牌作为I / p参数
  • In current code ideally redirect(work) shall also be awaited, async await shall be across the chain of calls 在当前代码中,理想情况下还应等待redirect(work) ,异步等待应贯穿整个调用链

Modified version of your code 您的代码的修改版本

With an assumption that you needs Task.WhenAll and you are doing IO based async, following shall be your code: 假设您需要Task.WhenAll并且您正在执行基于IO的异步操作,则以下代码应为:

protected override async Task ExecuteAsync(CancellationToken stoppingQueueToken,CancellationToken stopWorkToken)
{
      var work = await TaskQueue.DequeueAsync(stoppingQueueToken);
      List<Task> taskList = new List<Task>();
      while (!stoppingQueueToken.IsCancellationRequested)
      {  
         taskList.Add(redirect(work, stopWorkToken));
      }

      await Task.WhenAll(taskList);
}

public async Task redirect(Func<CancellationToken, Task> work, CancellationToken stopWorkToken)
{
    await work(stopWorkToken);
}

I have taken some liberty to introduce the Extra Cancellation Token for work Cancellation, since work processing only starts once while loop is exited, before that its just aggregating the tasks, then they are all processed in background together, assuming IO for maximum benefit. 我已经自由地介绍了用于工作取消的Extra Cancellation Token,因为工作处理仅在退出循环时才开始一次,在此之前它仅聚合任务,然后将它们一起在后台进行处理,并假定IO获得最大利益。 Here also debugger will block, but for all tasks together single call 在这里,调试器也会阻塞,但是对于所有任务,只需一次调用

If you persist with current code, then you just need to make following are the changes: 如果您坚持使用当前代码,则只需进行以下更改:

protected override async Task ExecuteAsync(CancellationToken stoppingQueueToken)
{
    var work = await TaskQueue.DequeueAsync(stoppingQueueToken);
    List<Task> taskList = new List<Task>();
    while (!stoppingQueueToken.IsCancellationRequested)
    {
        await redirect(work, stoppingQueueToken);
    }
}

public async Task redirect(Func<CancellationToken, Task> work, CancellationToken stoppingQueueToken)
{
    await work(stoppingQueueToken);
}
  • This code is going one after another, still async and releasing the calling context, but not all together. 这段代码接连进行,仍然异步并释放调用上下文,但不是全部一起。 Debugger will block as you have already seen. 如您所见,调试器将阻止。

Few more details 更多细节

  • Task and Thread are not same and interchangeable, multiple Tasks may be executed on same Thread TaskThread不相同且可以互换,多个任务可以在同一线程上执行
  • Cancellation Token is cooperative, it doesn't cancel an already started Task, either should be cancelled before Task begins or needs to be explicitly checked and Thrown to stop the Task Execution, ThrowIfCancellationRequested 取消令牌是协作的,它不会取消已启动的任务,应该在任务开始之前被取消,或者需要显式检查并抛出以停止任务执行, ThrowIfCancellationRequested

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

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