StackOverflow 20萬閱讀的問題:如何實現異步Task超時的處理

前文傳送門 dotNet開發基礎系列
C#異步編程基礎入門總結
C#泛型入門學習泛型類、泛型集合、泛型方法、泛型約束、泛型委託
C#異常處理總結
webapi token、參數簽名是如何生成的
C#擴展(2):Random的擴展
程序員:我終於知道post和get的區別
Try-Catch無法正確定位異常位置,我推薦2個有效技巧


之前在實際工作中,遇到過這樣的問題,異步獲取GPS定位信息。一個實際的問題出現了,在第一次定位的時候一般時間都比較長,現在的要做的是,當超出一定的時間,就提醒用戶。

Task.ContinueWith
可以實現異步等待任務完成
Task.Wait
可以實現同步等待完成任務後並超時,此方法會阻塞的線程,就是“卡界面”

那麼如何實現異步等待任務並在超時時進行一定的處理呢?

Task的實例方法 Wait

        public bool Wait(int millisecondsTimeout, CancellationToken cancellationToken);
        public bool Wait(int millisecondsTimeout);
        public bool Wait(TimeSpan timeout);
        public void Wait();
        public void Wait(CancellationToken cancellationToken);

Wait方法所支持的的特點:一個是取消任務,一個是超時。但是不可避免的是阻塞線程,一般在主線程中(UI線程)是要避免耗時任務的。如果真要去等待獲取定位信息的Task,會不可避免地卡住界面,用戶體驗不夠良好。

Task的靜態方法

在這裏插入圖片描述
Task.When** 可等待多個異步任務,不阻塞線程,所以可以利用Delay靜態方法“間接”實現異步超時的處理,非阻塞的方式!

var resultTask = Task.WhenAny(task, Task.Delay(timeout))

我們再WhenAny 方法中代入兩個task參數:源task、新建的延遲的task(ps:即超時的時間task),再得到resultTask。

        //
        // 摘要:
        //     任何提供的任務已完成時,創建將完成的任務。
        //
        // 參數:
        //   tasks:
        //     等待完成的任務。
        //
        // 返回結果:
        //     表示提供的任務之一已完成的任務。 返回任務的結果是完成的任務。
        public static Task<Task> WhenAny(params Task[] tasks);

異步Task 實現超時處理的方法

Task.WhenAny(task, Task.Delay(timeout)),再比較這兩個Task的執行先後。實現代碼如下:

        public static async Task<TResult> WaitAsync<TResult>(Task<TResult> task, TimeSpan timeout)
        {
            if (await Task.WhenAny(task, Task.Delay(timeout)) == task)
            {
                //指定時間內完成的處理
                return await task;
            }
            else
            {
                //超時處理
                throw new TimeoutException("The operation has timed out.");
            }
        }

思考

上述方法所實現的等待一個獲取gps的耗時任務,是沒有任何問題的。並不會產生性能、卡界面等問題,但是如果在源task(ps:執行獲取gps的task),在超時到期之前完成,則不會取消在Task.Delay調用中啓動的內部計時器作業。
當調用多次該方法時,“殭屍”計時器作業的數量變得越來越大時。性能可能會受到影響

參考鏈接

https://devblogs.microsoft.com/pfxteam/crafting-a-task-timeoutafter-method/

https://stackoverflow.com/questions/4238345/asynchronously-wait-for-taskt-to-complete-with-timeout

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章