使用HttpClient可以很方便的請求Web API,但在使用時有一些需要註意的地方,不然會給你的程式帶來毀滅性的問題。HttpClient是一個繼承了IDisposable介面的對象,所以在使用的時候,需要主動調用Dispose方法來釋放它。 ...
HttpClient
使用HttpClient可以很方便的請求Web API,但在使用時有一些需要註意的地方,不然會給你的程式帶來毀滅性的問題。
HttpClient是一個繼承了IDisposable
介面的對象,所以在使用的時候,需要主動調用Dispose
方法來釋放它。或者使用using
:
using(var client = new HttpClient()) { //do something with http client }
這看起來似乎沒什麼問題。我們使用一些代碼來測試一下它,我們將發起10個GET請求:
namespace ConsoleApplication { public class Program { public static async Task Main(string[] args) { Console.WriteLine("Starting connections"); for(int i = 0; i<10; i++) { using(var client = new HttpClient()) { var result = await client.GetAsync("http://www.zkea.net"); Console.WriteLine(result.StatusCode); } } Console.WriteLine("Connections done"); } } }
輸出結果如下:
Starting connections OK OK OK OK OK OK OK OK OK OK Connections done
看起來一切正常,但實際上並不是!我們使用netstat
來查看一下sockets的使用情況:
C:\Users\wayne>NETSTAT.EXE ... Proto Local Address Foreign Address State TCP 10.211.55.6:12050 47.74.132.243:http TIME_WAIT TCP 10.211.55.6:12051 47.74.132.243:http TIME_WAIT TCP 10.211.55.6:12053 47.74.132.243:http TIME_WAIT TCP 10.211.55.6:12054 47.74.132.243:http TIME_WAIT TCP 10.211.55.6:12055 47.74.132.243:http TIME_WAIT TCP 10.211.55.6:12056 47.74.132.243:http TIME_WAIT TCP 10.211.55.6:12057 47.74.132.243:http TIME_WAIT TCP 10.211.55.6:12058 47.74.132.243:http TIME_WAIT TCP 10.211.55.6:12059 47.74.132.243:http TIME_WAIT TCP 10.211.55.6:12060 47.74.132.243:http TIME_WAIT TCP 10.211.55.6:12061 47.74.132.243:http TIME_WAIT TCP 10.211.55.6:12062 47.74.132.243:http TIME_WAIT ...
雖然應用程式已經退出,但是剛纔發起的連接仍處於 TIME_WAIT
狀態。TIME_WAIT
狀態是指連接已經在一邊關閉,但仍在等待是否有其他數據包出現, 因為它們可能在網路上的某個地方被延遲,socket資源並沒有立即被回收。所以,如果你的程式(網站)的併發量很大,而每一次都實例化一個HttpClient對象,你的程式將會消耗掉伺服器上所有可用的socket資源,並導致程式出現異常,不可正常訪問。
正確使用HttpClient
HttpClient裡面的方法都是線程安全的:
CancelPendingRequests DeleteAsync GetAsync GetByteArrayAsync GetStreamAsync GetStringAsync PostAsync PutAsync SendAsync
所以你應當只實例化一個HttpClient對象,並且不需要去主動釋放它,它會在你程式退出的時候一起被釋放掉。
我們對程式做以下修改再測試一下:
namespace ConsoleApplication { public class Program { private static HttpClient Client = new HttpClient(); public static async Task Main(string[] args) { Console.WriteLine("Starting connections"); for(int i = 0; i<10; i++) { var result = await Client.GetAsync("http://aspnetmonsters.com"); Console.WriteLine(result.StatusCode); } Console.WriteLine("Connections done"); Console.ReadLine(); } } }
再看看socket使用情況,這下就一切正常了:
TCP 10.211.55.6:12254 47.74.132.243:http ESTABLISHED
原文鏈接:http://www.zkea.net/codesnippet/detail/post-122.html