不知道用什么詞形容,就叫它假異步吧。
寫異步方法,async 和 await 要一路寫到底,否則就是假異步,並不能提高請求線程池的吞吐量。
真正的異步,我的理解是這樣的:比如調用一個查詢接口,在當前線程,把SQL扔給數據庫,當前線程釋放,去干別的事情,數據庫查詢完了,通知我,我再在另一個線程里(也可能是剛才釋放的那個線程,也可能不是)拿查詢結果,返回給客戶端,數據庫查詢比較耗時,數據庫查詢的時候,對線程是0占用。
HttpUtil.HttpGet方法:

/// <summary> /// HttpGet /// </summary> /// <param name="url">url路徑名稱</param> /// <param name="cookie">cookie</param> public static string HttpGet(string url, CookieContainer cookie = null, WebHeaderCollection headers = null) { try { // 設置參數 HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest; request.CookieContainer = cookie; request.Method = "GET"; request.ContentType = "text/plain;charset=utf-8"; if (headers != null) { foreach (string key in headers.Keys) { request.Headers.Add(key, headers[key]); } } //發送請求並獲取相應回應數據 HttpWebResponse response = request.GetResponse() as HttpWebResponse; //直到request.GetResponse()程序才開始向目標網頁發送Post請求 Stream instream = response.GetResponseStream(); StreamReader sr = new StreamReader(instream, Encoding.UTF8); //返回結果網頁(html)代碼 string content = sr.ReadToEnd(); instream.Close(); return content; } catch (Exception ex) { LogUtil.Error(ex); return string.Empty; } }
HttpUtil.HttpGetAsync方法:

/// <summary> /// HttpGetAsync /// </summary> /// <param name="url">url路徑名稱</param> /// <param name="cookie">cookie</param> public static async Task<string> HttpGetAsync(string url, CookieContainer cookie = null, WebHeaderCollection headers = null) { try { // 設置參數 HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest; request.CookieContainer = cookie; request.Method = "GET"; request.ContentType = "text/plain;charset=utf-8"; if (headers != null) { foreach (string key in headers.Keys) { request.Headers.Add(key, headers[key]); } } //發送請求並獲取相應回應數據 HttpWebResponse response = await request.GetResponseAsync() as HttpWebResponse; //直到request.GetResponse()程序才開始向目標網頁發送Post請求 Stream instream = response.GetResponseStream(); StreamReader sr = new StreamReader(instream, Encoding.UTF8); //返回結果網頁(html)代碼 string content = sr.ReadToEnd(); instream.Close(); return content; } catch (Exception ex) { LogUtil.Error(ex); return string.Empty; } }
測試代碼:

/// <summary> /// 測試1 /// </summary> private async void button1_Click(object sender, EventArgs e) { //task是自己寫的獨立線程池,為了防止測試過程對CLR線程池和異步線程池造成干擾 _task.Run(() => { Thread.Sleep(200); int workerThreads1, completionPortThreads1, workerThreads2, completionPortThreads2; ThreadPool.GetMaxThreads(out workerThreads1, out completionPortThreads1); ThreadPool.GetAvailableThreads(out workerThreads2, out completionPortThreads2); Log("假異步 已使用輔助線程:" + (workerThreads1 - workerThreads2) + ", 已使用異步線程:" + (completionPortThreads1 - completionPortThreads2)); }); string str = await GetDataAsync(); } /// <summary> /// 測試2 /// </summary> private async void button2_Click(object sender, EventArgs e) { //task是自己寫的獨立線程池,為了防止測試過程對CLR線程池和異步線程池造成干擾 _task.Run(() => { Thread.Sleep(200); int workerThreads1, completionPortThreads1, workerThreads2, completionPortThreads2; ThreadPool.GetMaxThreads(out workerThreads1, out completionPortThreads1); ThreadPool.GetAvailableThreads(out workerThreads2, out completionPortThreads2); Log("真異步 已使用輔助線程:" + (workerThreads1 - workerThreads2) + ", 已使用異步線程:" + (completionPortThreads1 - completionPortThreads2)); }); string str = await GetDataAsync2(); } /// <summary> /// 假異步 /// </summary> private async Task<string> GetDataAsync() { return await Task.Run<string>(() => { //接口耗時大約1秒 return HttpUtil.HttpGet("http://localhost:8500/api/test/TestGet?val=1", null, null); }); } /// <summary> /// 真異步 /// </summary> /// <returns></returns> private async Task<string> GetDataAsync2() { //接口耗時大約1秒 return await HttpUtil.HttpGetAsync("http://localhost:8500/api/test/TestGet?val=1", null, null); }
測試截圖:
我想知道 WebRequest 類的 GetResponseAsync 方法是怎么實現的,反正使用.NET提供的類,我是無法實現這樣的方法。
這篇隨筆如果有錯誤,請指正,我只是拋磚引玉,提出疑問或者說假設。
async await 要一路寫到底啊,重構壓力真大。
如果在異步方法中調用同步方法,又不想占用CLR線程池的線程,可以把耗時操作放到自己寫的獨立線程池中,例如:

/// <summary> /// 測試GET請求 /// </summary> /// <param name="val">測試參數</param> [HttpGet] [Route("TestGet")] [SwaggerResponse(HttpStatusCode.OK, "返回JSON", typeof(JsonListResult<TestGetResult>))] public async Task<HttpResponseMessage> TestGetAsync(string val) { var task = TaskHelper.RequestTask.Run(() => //使用自己寫的獨立線程池 { List<TestGetResult> list = new List<TestGetResult>(); Thread.Sleep(5000); //模擬耗時 for (int i = 1; i <= 10; i++) { TestGetResult item = new TestGetResult(); item.testValue1 = i.ToString(); item.testValue2 = i; item.testValue3 = "這是傳入參數:" + val; list.Add(item); } var jsonResult = new JsonListResult<TestGetResult>(list, list.Count); return ApiHelper.ToJson(jsonResult); }); return await task; }