簡體   English   中英

如何取消異步任務?

[英]How to cancel an asynchronous Task?

我有一個加載數據的方法,例如:

public async GetCustomers()
{
    await Task.Run(() => {
        for (int i = 0; i < 99; i++)
            customers = customerRequest.GetCustomers();
    });
}

customerRequest是一個使用HttpClient連接到WebApi服務器的簡單類。 調用堆棧如下:

method-> request-> controller action-> server layer-> repository-> db

目前,控制器操作返回IHttpActionResult ,而服務和存儲庫層返回IEnumerable<Customer> 所有方法都是同步調用的。

出於測試目的,我添加了for循環以增加任務的延遲並查看正在執行的SQL語句。

如果用戶決定關閉表單,則任務仍在后台執行,SQL語句仍會發送到數據庫。

取消此類任務的正確方法是什么?

您想要使用CancellationTokenSource ,並將其CancellationToken傳遞給您的方法。 表單關閉時,調用CancellationTokenSource.Cancel

但請注意,您希望將CancellationToken傳遞給實際使用它的方法。 正如我在博客中描述的那樣, Task.Run不是其中之一

你真正想要做的是從最低級別(在客戶端)開始,並將CancellationToken傳遞給你正在使用的任何HttpClient方法(即, 像這樣 )。

然后繼續努力。 我還建議讓你的代碼異步。 當你完成后,你應該得到一個如下所示的GetCustomers

public async Task GetCustomersAsync(CancellationToken token)
{
  for (int i = 0; i < 99; i++)
    customers = await customerRequest.GetCustomersAsync(token);
}

如果你真的想確定(tm)沒有虛假請求,你也可以在做請求之前明確檢查令牌:

public async Task GetCustomersAsync(CancellationToken token)
{
  for (int i = 0; i < 99; i++)
  {
    token.ThrowIfCancellationRequested();
    customers = await customerRequest.GetCustomersAsync(token);
  }
}

如果這對您很重要,您還可以在服務器端處理取消

Checkout CancellationTokenSource。 您可以保留其中一個長壽命按鈕或關閉事件調用取消()。 如果您希望取消所有任務,只需將其傳遞給您的所有任務。 該任務將拋出異常,因此請確保包裝try catch。 您還可以檢查您的任務中是否已取消取消請求以嘗試以優雅的方式突破。

var cts = new CancellationTokenSource();

await Task.Run(() =>
{
    //do work, will throw if cts.Cancel() is called
}, cts.Token);

//wait 2 seconds then cancel
await Task.Delay(2000);

cts.Cancel();

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM