簡體   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