.NET(C#):用3種方式來實現非同步取消Task後向當前SynchronizationContext執行操作

來源:互聯網
上載者:User

.NET TPL擁有非常大的靈活性,你會發現同一個操作會有許多不同的實現方式。正如標題所講,我們來看這樣一個簡答的操作:取消Task的執行,然後在當前SynchronizationContext中執行代碼。當然一切操作都必須是非同步,因此不能使用Task.Wait這樣的方法。

我想到的實現方法有三種。

 

首先是準備工作,先寫一個方法用來執行一個可以取消的Task,之後的具體實現代碼就直接調用這個方法:

//執行一個可以取消的Task

static Task NewCancellableTask(CancellationToken token)

{

    return Task.Run(() =>

        {

            while (true)

            {

                System.Threading.Thread.Sleep(1000);

                token.ThrowIfCancellationRequested();

            }

        });

}

 

接下來看三種具體實現。

目錄

  • 方法一:使用await
  • 方法二:使用ContinueWith和TaskScheduler
  • 方法三:使用CancellationToken.Register方法

 

返回目錄
方法一:使用await

這必須是首選,C# 5.0的await隱藏了許多TPL中的邏輯,以至於可以使非同步執行的代碼從外表上看起來和同步執行沒太大區別。如下代碼:

var cts = new CancellationTokenSource();

//執行取消操作

cts.CancelAfter(1000);

try

{

    await NewCancellableTask(cts.Token);

}

catch (OperationCanceledException)

{

    //收集OperationCanceledException

    MessageBox.Show("操作取消");

}

運行幾秒鐘後,會顯示“操作取消”對話方塊。

 

 

返回目錄
方法二:使用ContinueWith和TaskScheduler

第二種方法我使用Task.ContinueWith,並且使用:

TaskContinuationOptions.OnlyOnCanceled

來確保只有在Task被取消後,後續操作才會被執行。

 

由於沒有用await,因此SynchronizationContext的執行需要我們自己來做,方法就是使用TaskScheduler.FromCurrentSynchronizationContext方法來返回一個從當前SynchronizationContext建立的TaskScheduler。

 

Task.ContinueWith有諸多重載,我們使用這一個:

Task<TResult> ContinueWith<TResult>(Func<Task, TResult> continuationFunction, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler);

 

最終代碼:

var cts = new CancellationTokenSource();

//執行取消操作

cts.CancelAfter(1000);

//ContinueWith

NewCancellableTask(cts.Token).ContinueWith(

    t => MessageBox.Show("操作取消"),

    CancellationToken.None,

    TaskContinuationOptions.OnlyOnCanceled,

    TaskScheduler.FromCurrentSynchronizationContext());

(ContinueWith的Task事實上返回一個Task<MessageBoxResult>)

 

同樣,運行成功。

 

返回目錄
方法三:使用CancellationToken.Register方法

CancellationToken類型有一個Register方法可以傳入一個委託,當CancellationToken被取消後這個委託會被調用。更不可思議的是,它還有一個useSynchronizationContext參數來指定是否回調方法被執行在當前SynchronizationContext上,非常給力。當然Register方法還可以傳遞一個額外參數,本例不需要使用。

 

:CancellationToken.Register方法的參數:

 

那麼使用這種方法的實現代碼:

var cts = new CancellationTokenSource();

//註冊操作

cts.Token.Register(() => MessageBox.Show("操作取消"), true);

//執行取消操作

cts.CancelAfter(1000);

//直接執行Task,不需要其他動作。

NewCancellableTask(cts.Token);

 

這種方法比較少見,不過看起來還不錯。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.