C# HttpClient使用和注意事項,.NET Framework連接池併發限制

System.Net.Http.HttpClient 類用於發送 HTTP 請求以及從 URI 所標識的資源接收 HTTP 響應。 HttpClient 實例是應用於該實例執行的所有請求的設置集合,每個實例使用自身的連接池,該池將其請求與其他請求隔離開來。 從 .NET Core 2.1 開始,SocketsHttpHandler 類提供實現,使行爲在所有平臺上保持一致。

HttpClient實例是執行網絡請求的設置集合,每個實例會使用一個連接池。通過這段描述我們知道實際使用HttpClient的時候我們只需要實例化一個就行了,在處理程序實例內池連接,並在多個請求之間重複使用連接。也就是官方提倡的使用單個實例,如果每次請求就實例化一個HttpClient,則會創建不必要的連接降低性能,並且TCP 端口不會在連接關閉後立即釋放。

所以如果是大批量創建HttpClient請求則大量負載下可用的套接字數將耗盡,這種耗盡將導致 SocketException 錯誤。

使用方式

  1. 使用靜態變量。
static readonly HttpClient httpClient = new HttpClient();

  1. 使用單例模式
    public class HttpClientInstance
    {
        private static readonly HttpClient _HttpClient;

        static HttpClientInstance()
        {
            _HttpClient = new HttpClient();
        }

        public static HttpClient GetHttpClient()
        {
            return _HttpClient;
        }
    }

實例化參數

可以通過構造參數(如 HttpClientHandler (或 SocketsHttpHandler .NET Core 2.1 或更高版本) )作爲構造函數的一部分來配置其他選項。 實例化HttpClient後無法更連接屬性,因此,如果需要更改連接屬性,則需要創建新的 HttpClient 實例。

配置可以在構造期間配置 HttpClientHandler 或 SocketsHttpHandler 傳入,SocketsHttpHandler可以設置額外參數包括 MaxConnectionsPerServer, PooledConnectionIdleTimeout、PooledConnectionLifetime、ConnectTimeout。

  • MaxConnectionsPerServer:HttpClient 對象所允許的最大併發連接數。
  • PooledConnectionIdleTimeout: PooledConnectionLifetime 指定的時間範圍過後,系統會關閉連接,然後創建一個新連接。
  • PooledConnectionLifetime:指定要用於連接池中每個連接的超時值。 如果連接處於空閒狀態,則連接會立即關閉;否則,連接在當前請求結束時關閉。
  • ConnectTimeout:指定在請求需要創建新的 TCP 連接時使用的超時。 如果發生超時,將取消請求 Task
var handler = new SocketsHttpHandler
{
    PooledConnectionLifetime = TimeSpan.FromMinutes(15)
};
var httpClient = new HttpClient(handler);

在.NET Framework 只能使用HttpClientHandler,且沒有PooledConnectionIdleTimeout和PooledConnectionLifetime等參數。

HttpClientHandler httpClientHandler = new HttpClientHandler();
//最大併發連接數
httpClientHandler.MaxConnectionsPerServer = 100;

HttpClient httpClient=new HttpClient(httpClientHandler);
//超時設置
httpClient.Timeout = new TimeSpan(5000);

可以是設置MaxConnectionsPerServer,可以設置Timeout。Timeout 爲來自 HttpClient 實例的所有 HTTP 請求設置默認超時。 超時僅適用於導致啓動請求/響應的 xxxAsync 方法。 如果達到超時,則會 Task 取消該請求。這個超時時間是包含從請求到響應的整個時間段,而不像上面參數可以設置連接超時。

請求實現

HttpClient這是一個高級 API,用於包裝其運行的每個平臺上可用的較低級別功能。

在每個平臺上, HttpClient 嘗試使用最佳可用傳輸:
image

注意事項

在上面實現可以看到在不同的框架下HttpClient的實現是不一樣的,在.NET Framework下是使用HttpWebRequest支持。

所以還會受限HttpWebRequest的實現,如果我們要啓用多線程高頻率調用接口,那麼這裏要注意HttpWebRequest的連接併發的數量限制。HttpWebRequest通過ServicePoint設置,我們通過反編譯看到HttpWebRequest構造函數。
image

ServicePoint.DefaultConnectionLimit獲取允許的最大併發連接數。 對於 ASP.NET 託管的應用程序,默認連接限制爲 10,對於所有其他應用程序,默認連接限制爲 2。DefaultConnectionLimit 對現有 ServicePoint 對象沒有影響;它隻影響更改後初始化的對象。如果未直接或通過配置設置此屬性的值,則該值默認爲常量 DefaultPersistentConnectionLimit

image

如果是應用連接池默認只有2個併發,所以當你啓用很多線程的時候實際效率是不會提升的,一直只有兩個併發在阻塞排隊,如果請求比較耗時後面的請求還有異常的可能。

因此當你使用多線程的時候要注意初始化HttpClient的httpClientHandler.MaxConnectionsPerServer = n;該參數用於設置。

RestSharp

平時我們可能使用RestSharp 用於網絡請求,實際也是在HttpWebRequest上的封裝,在官網我們可以看到如下說明:
image

在最新的v107換成了HttpClient,以前的版本也是HttpWebRequest。如果要設置RestSharp的連接池併發數需要修改默認值。

System.Net.ServicePointManager.DefaultConnectionLimit = n;

然後再實例化RestClient。

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