繁体   English   中英

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

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

我是asp.net核心和异步编程的新手。 下面是我的代码

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();
}

所以在这里,当我运行程序并调试它时,光标首先进入ExecuteAsync方法,而从while循环进入重定向方法。 重定向方法仍然是异步的,它将等待工作方法。 所以我认为它不是异步运行的。

我希望当光标进入工作方法时,它将启动一个新任务(线程)。

当我运行程序并对其进行调试时

您正在观察的行为是Visual Studio 试图提供帮助。 它具有处理异步方法的特殊代码,因此,当您说“进入下一行”时,它不会突然转移到某些完全不相关的方法。 它将转到该方法的下一行。

我希望当光标进入工作方法时,它将启动一个新任务(线程)。

任务不是线程。 特别是, async方法创建的任务不会在线程上运行; 它们只是状态对象,可以在async方法完成时通知其他代码。

我建议阅读我的async介绍 ,并通过async最佳实践进行跟进。

您尝试使用Async-Await的方式存在一些误解,网络上有足够的内容,以下是详细信息:

所以在这里,当我运行程序并调试它时,光标首先进入ExecuteAsync方法,而从while循环进入重定向方法。 重定向方法仍然是异步的,它将等待工作方法。 所以我认为它不是异步运行的

await所做的是释放调用上下文,而处理在后台进行,这有助于系统保持响应状态,因此系统具有可伸缩性/线程池来满足进一步的请求,因此, await唯一不做的事情就是阻塞调用线程/上下文中,在代码中看到的调试器中,它将等待完成。

现在,什么类型的处理work是IO还是Compute

如果是IO ,那就是真正在服务器上使用异步处理的地方,因为线程池线程已释放,并且如果与ConfigureAwait(false)一起使用,则不需要重新输入相同的上下文来处理响应,这是库期望的。 如果是计算的,那么它就可以像WPF这样的UI很好地工作,因为Ui线程保持了响应能力,但是处理仍然从当前池中夺走了线程,并且可用性有限/稀缺。

关于你的代码

  • 在当前形式下,它是一个阻塞代码,因为在while循环中,您正在调用redirect(work) ,而后者又确实await work ,它释放了调用者,但等待它完成才能执行下一个Async操作
  • 理想的方式是将所有任务收集在List<Task>类的集合中,并在等待Task.WhenAll时将所有聚合的任务放在一起,而当您异步等待单个代表性Task使其完成时,仍然可以不是像当前代码中那样大胆地调用,而是阻止完整的聚合列表,它由@TheGeneral在注释中指定,因此有助于更好地处理,因为所有任务都一起执行
  • 另外await work()不正确,编译错误,这需要一个取消令牌作为I / p参数
  • 在当前代码中,理想情况下还应等待redirect(work) ,异步等待应贯穿整个调用链

您的代码的修改版本

假设您需要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);
}

我已经自由地介绍了用于工作取消的Extra Cancellation Token,因为工作处理仅在退出循环时才开始一次,在此之前它仅聚合任务,然后将它们一起在后台进行处理,并假定IO获得最大利益。 在这里,调试器也会阻塞,但是对于所有任务,只需一次调用

如果您坚持使用当前代码,则只需进行以下更改:

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);
}
  • 这段代码接连进行,仍然异步并释放调用上下文,但不是全部一起。 如您所见,调试器将阻止。

更多细节

  • TaskThread不相同且可以互换,多个任务可以在同一线程上执行
  • 取消令牌是协作的,它不会取消已启动的任务,应该在任务开始之前被取消,或者需要显式检查并抛出以停止任务执行, ThrowIfCancellationRequested

暂无
暂无

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

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