異步編程的概念我在第一章概要的時候,說起了。在此再次簡略概要一次。編程
它採用future模式或者回調模式機制,以免產生沒必要要的線程。
在第一個寫這個的緣由,是由於測試可能比開發重要。由於在開發一個項目的時候呢?有一個自動化高效精準測試,決定了上線是否穩定。由於程序出bug測試出來能夠改,方案不行換方案,可是測試不行上線了。這時候面臨的問題就比較大,由於這時候產生了數據。api
好比說 app 一張表的設計不合理,在自動化測試中沒有體現出來,那麼你要更換表的時候就顯得異常困難,這時候到底換不換表的結構呢?換了以後,如何兼容以前的版本?迭代的方案是啥。好的,扯得很遠了。app
固然咱們做爲開發人員也要作好單元測試,及子系統測試。好的,近了一點了。異步
咱們在寫一個異步程序的時候,是有3個測試必須經過。async
1.同步成功異步編程
2.異步成功單元測試
3.異步失敗測試
先介紹一下如何異步測試:url
public static async Task<T> DelayResult<T>(T result, TimeSpan delay) { await Task.Delay(delay); return result; }
如何測試的時候若是這樣寫:線程
[Fact] public async void Test1() { TimeSpan timeSpan = new TimeSpan(); Program.DelayResult<int>(1, timeSpan); }
那麼這個測試是有問題的。
好比:
public static async Task<T> DelayResult<T>(T result, TimeSpan delay) { await Task.Delay(delay); throw new Exception("error"); return result; }
原本我是應該拋出異常的,可是:
結果是下面這樣的。
緣由就涉及到一個異常捕獲的問題了,能夠查詢一下原理。
運行測試的時候應該加上await:
[Fact] public async void Test1() { TimeSpan timeSpan = new TimeSpan(); await Program.DelayResult<int>(1, timeSpan); }
那麼這個時候就能夠捕獲到異常。
下面介紹一些例子。
這個是什麼意思呢?好比說,咱們訪問咱們的一條url的時候,訪問失敗。
接下來咱們應該作的是重試,那麼是否立刻重試?不是的,除非是阻塞式的api調用,例如登陸。
可是呢,若是不是阻塞式的,那麼應該把資源分配均衡。由於你一次失敗,第二次的也有可能失敗。
那麼這時候指數退避是一種良好的方法。
static async Task<string> visitUrl(string url) { using (var client = new HttpClient()) { var nextDelay = TimeSpan.FromSeconds(1); for (int i = 0; i != 3; ++i) { try { return await client.GetStringAsync(url); } catch { } await Task.Delay(nextDelay); nextDelay = nextDelay + nextDelay; } // 返回最後的結果方便得出錯誤 return await client.GetStringAsync(url); } }
測試:
[Fact] public async void Test1() { await Program.visitUrl("www.xxx.com"); }
結果:
測試花了7秒。
正確驗證測試我就不測了。
上面的這個代碼,咱們發現一個問題啊,若是訪問那個連接要很久,那麼這也很受傷啊。
是否能加入一個超時,若是訪問一段時間沒有返回結果,那麼把資源留給別的需求者。
public static async Task<string> visitTimeoutUrl(HttpClient client,string url) { var visitTask=client.GetStringAsync(url); var timeoutTask = Task.Delay(3000); var completedTask = await Task.WhenAny(visitTask,timeoutTask); if (completedTask == timeoutTask) { return null; } return await visitTask; }
上文實現了一個簡單的超時。
而後改一下:
public static async Task<string> visitUrl(string url) { using (var client = new HttpClient()) { var nextDelay = TimeSpan.FromSeconds(1); for (int i = 0; i != 3; ++i) { try { var result= await visitTimeoutUrl(client,url); if (result != null) { return result; } } catch { } await Task.Delay(nextDelay); nextDelay = nextDelay + nextDelay; } // 返回最後的結果方便得出錯誤 return await visitTimeoutUrl(client, url); } }
今天寫博客的時候,一直出現error,就先到這吧。 下一章,仍是幾個例子感覺一下。以上爲我的理解,若有不對望請指出。