問題:git
須要讓程序(以異步方式)等待一段時間。github
解決方案:Task類的靜態函數Delay,返回Task對象windows
在github開源項目dotnet/coreclr
,找到Task.cs有關Delay方法的源碼
github地址:
https://github.com/dotnet/coreclr/blob/master/src/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs服務器
/// <summary> /// Creates a Task that will complete after a time delay. /// </summary> /// <param name="millisecondsDelay">The number of milliseconds to wait before completing the returned Task</param> /// <returns>A Task that represents the time delay</returns> /// <exception cref="T:System.ArgumentOutOfRangeException"> /// The <paramref name="millisecondsDelay"/> is less than -1. /// </exception> /// <remarks> /// After the specified time delay, the Task is completed in RanToCompletion state. /// </remarks> public static Task Delay(int millisecondsDelay) { return Delay(millisecondsDelay, default); }
Delay方法會建立一個延遲millisecondsDelay
毫秒後完成的任務。
millisecondsDelay
爲 在完成返回的任務前要等待的毫秒數,若是值爲-1,將無限期等待。app
Delay方法有多個重載方法,以下less
public static Task Delay(TimeSpan delay); public static Task Delay(TimeSpan delay, CancellationToken cancellationToken); public static Task Delay(int millisecondsDelay); public static Task Delay(int millisecondsDelay, CancellationToken cancellationToken);
書中給出三個例子。
一個是單元測試中,定義一個異步完成的任務,以完成「異步成功」測試。異步
static async Task<T> DelayResult<T>(T result, TimeSpan delay) { await Task.Delay(delay); return result; }
一個是指數退避的簡單實現。async
指數退避是一種重試策略,重試的延遲時間會逐次增長。在訪問 Web 服務時,最好的方式就是採用指數退避,它能夠防止服務器被太多的重試阻塞。函數
書中提到實際產品開發中,應對指數退避重試機制有更周密的解決方案。書中推薦了微軟企業庫中的瞬間錯誤處理模塊(Transient Error Handling Block),在微軟Docs中找到了相關文章。
暫時性故障處理 (構建使用 Azure 的真實世界雲應用程序):
https://docs.microsoft.com/zh-cn/aspnet/aspnet/overview/developing-apps-with-windows-azure/building-real-world-cloud-apps-with-windows-azure/transient-fault-handling單元測試
static async Task<string> DownloadStringWithRetries(string uri) { using (var client = new HttpClient()) { // 第 1 次重試前等 1 秒,第 2 次等 2 秒,第 3 次等 4 秒。 var nextDelay = TimeSpan.FromSeconds(1); for (var i = 0; i != 3; ++i) { try { return await client.GetStringAsync(uri); } catch { } await Task.Delay(nextDelay); nextDelay = nextDelay + nextDelay; } // 最後重試一次,以便讓調用者知道出錯信息。 return await client.GetStringAsync(uri); } }
上述代碼實現的是對異步get請求進行屢次重試。
最後一個例子,是實現了一個簡單的超時功能,當get請求在3秒內沒有響應,返回null。
static async Task<string> DownloadStringWithTimeout(string uri) { using (var client = new HttpClient()) { var downloadTask = client.GetStringAsync(uri); var timeoutTask = Task.Delay(3000); var completedTask = await Task.WhenAny(downloadTask, timeoutTask); if (completedTask == timeoutTask) return null; return await downloadTask; } }
該代碼的實現主要是藉助於Task.WhenAny
方法。
Task.WhenAny
的返回值是提供的多個任務中已完成的任務。
若是已完成的任務completedTask
和timeoutTask
相等,證實最早完成的任務是等待三秒以後完成的任務timeoutTask
,也就是說downloadTask
沒有在三秒內完成。