欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C#中HttpClient使用注意(預(yù)熱與長連接)

 更新時間:2022年02月14日 10:29:53   作者:dudu  
本文主要介紹了C#中HttpClient使用,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下

最近在測試一個第三方API,準備集成在我們的網(wǎng)站應(yīng)用中。API的調(diào)用使用的是.NET中的HttpClient,由于這個API會在關(guān)鍵業(yè)務(wù)中用到,對調(diào)用API的整體響應(yīng)速度有嚴格要求,所以對HttpClient有了格外的關(guān)注。

開始測試的時候,只在客戶端通過HttpClient用PostAsync發(fā)了一個http post請求。測試時發(fā)現(xiàn),從創(chuàng)建HttpClient實例,到發(fā)出請求,到讀取到服務(wù)器的響應(yīng)數(shù)據(jù)總耗時在2s左右,而且多次測試都是這樣。2s的響應(yīng)速度當然是無法讓人接受的,我們希望至少控制在100ms以內(nèi)。于是開始追查這個問題的原因。

在API的返回數(shù)據(jù)中包含了該請求在服務(wù)端執(zhí)行的耗時,這個耗時都在20ms以內(nèi),問題與服務(wù)端API無關(guān)。于是把懷疑點放到了網(wǎng)絡(luò)延遲上,但ping服務(wù)器的響應(yīng)時間都在10ms左右,網(wǎng)絡(luò)延遲的可能性也不大。

當我們正準備換一個網(wǎng)絡(luò)環(huán)境進行測試時,突然想到,我們的測試方式有些問題。我們只通過HttpClient發(fā)了一個PostAsync請求,假如HttpClient在第一次調(diào)用時存在某種預(yù)熱機制(比如在EF中就有這樣的機制),現(xiàn)在2s的總耗時可能大多消耗在HttpClient的預(yù)熱上。

于是修改測試代碼,將調(diào)用由1次改為100次,然后恍然大悟地發(fā)現(xiàn)——只有第1次是2s,接下來的99次都在100ms以內(nèi)。果然是HttpClient的某種預(yù)熱機制在搞鬼!

既然知道了是HttpClient預(yù)熱機制的原因,那我們可以幫HttpClient進行熱身,減少第一次請求的耗時。我們嘗試了一種預(yù)熱方式,在正式發(fā)http post請求之前,先發(fā)一個http head請求,代碼如下:

_httpClient.SendAsync(new HttpRequestMessage {
? ? ? ? ? ? ? ? ? ? Method = new HttpMethod("HEAD"),?
? ? ? ? ? ? ? ? ? ? RequestUri = new Uri(BASE_ADDRESS + "/") })
? ? ? ? ? ? ? ? .Result.EnsureSuccessStatusCode();

經(jīng)測試,通過這種熱身方法,可以將第一次請求的耗時由2s左右降到1s以內(nèi)(測試結(jié)果是700多ms)。

在知道第1次HttpClient請求耗時2s的真相之后,我們將目光轉(zhuǎn)向了剩下的99次耗時100ms以內(nèi)的請求,發(fā)現(xiàn)絕大部分請求都在50ms以上。有沒有可能將之降至50ms以下?而且,之前一直有這樣的糾結(jié):每次調(diào)用是不是一定要對HttpClient進行Dispose()?是不是要將HttpClient單例或者靜態(tài)化(聲明為靜態(tài)變量)?借此機會一起研究一下。

在HttpClient的背后,有一個對請求響應(yīng)速度有著不容忽視影響的東東——TCP連接。一個HttpClient實例會關(guān)聯(lián)一個TCP連接,在對HttpClient進行Dispose時,會關(guān)閉TCP連接(我們用Wireshark進行網(wǎng)絡(luò)抓包也驗證了這一點)。

在之前的測試中,我們每次用HttpClient發(fā)請求時,都是新建一個HttpClient實例,用完就對它進行Dispose,代碼如下:

using (var httpClient = new HttpClient() { BaseAddress = new Uri(BASE_ADDRESS) })
{
? ? httpClient.PostAsync("/", new FormUrlEncodedContent(parameters));
}

所以每次請求時都要經(jīng)歷新建TCP連接->傳數(shù)據(jù)->關(guān)閉連接(也就是通常所說的短連接),而且雪上加霜的是請求用的是https,建立TCP連接時還需要一個基于公私鑰加解密的key exchange過程:Client Hello -> Server Hello -> Certificate -> Client Key Exchange -> New Session Ticket。

如果我們想將請求響應(yīng)時間降至50ms以下,就必須從這個地方下手——重用TCP連接(也就是通常所說的長連接)。要實現(xiàn)長連接,首先需要的就是在HttpClient第1次請求后不關(guān)閉TCP連接(不調(diào)用Dispose方法);而要讓后續(xù)的請求繼續(xù)使用這個未關(guān)閉的TCP連接,我們必須要使用同一個HttpClient實例;而要使用同一個HttpClient實例,就得實現(xiàn)HttpClient的單例或者靜態(tài)化。之前的3 個問題,由于要解決第1個問題,后2個問題變成了別無選擇。

為了實現(xiàn)長連接,我們將HttpClient的調(diào)用代碼改為如下的樣子:

然后測試一下請求響應(yīng)時間:

  Elapsed:750ms
  Elapsed:31ms
  Elapsed:30ms
  Elapsed:43ms
  Elapsed:27ms
  Elapsed:29ms
  Elapsed:28ms
  Elapsed:35ms
  Elapsed:36ms
  Elapsed:31ms
  ....

除了第1次請求,接下來的99次請求絕大多數(shù)都在50ms以內(nèi)。TCP長連接的效果必須的!

通過Wireshak抓包也驗證了長連接的效果:

Wireshak抓包

這時,你

public class HttpClientTest
{?
? ? private static readonly HttpClient _httpClient;

? ? static HttpClientTest()
? ? {
? ? ? ? _httpClient = new HttpClient() { BaseAddress = new Uri(BASE_ADDRESS) };

? ? ? ? //幫HttpClient熱身
? ? ? ? _httpClient.SendAsync(new HttpRequestMessage {
? ? ? ? ? ? ? ? Method = new HttpMethod("HEAD"),?
? ? ? ? ? ? ? ? RequestUri = new Uri(BASE_ADDRESS + "/") })
? ? ? ? ? ? .Result.EnsureSuccessStatusCode();
? ? }

? ? public async Task<string> PostAsync()
? ? {
? ? ? ? var response = await _httpClient.PostAsync("/", new FormUrlEncodedContent(parameters));

? ? ? ? return await response.Content.ReadAsStringAsync();
? ? }
}

也許會產(chǎn)生這樣的疑問:將HttpClient聲明為靜態(tài)變量,會不會存在線程安全問題?我們當時也有這樣的疑問,后來在stackoverflow上找到了答案

As per the comments below (thanks @ischell), the following instance methods are thread safe (all async):
CancelPendingRequests
DeleteAsync
GetAsync
GetByteArrayAsync
GetStreamAsync
GetStringAsync
PostAsync
PutAsync
SendAsync

HttpClient的所有異步方法都是線程安全的,放心使用。

到這里,HttpClient的問題是不是可以完美收官了?。。。稍等,還有一個問題。

客戶端雖然保持著TCP連接,但TCP連接是兩口子的事,服務(wù)器端呢?你不告訴服務(wù)器,服務(wù)器怎么知道你要一直保持TCP連接呢?對于客戶端,保持TCP連接的開銷不大;但是對于服務(wù)器,則完全不一樣的,如果默認都保持TCP連接,那可是要保持成千上萬客戶端的連接啊。所以,一般的Web服務(wù)器都會根據(jù)客戶端的訴求來決定是否保持TCP連接,這就是keep-alive存在的理由。

所以,我們還要給HttpClient增加一個Connection:keep-alive的請求頭,代碼如下:

_httpClient.DefaultRequestHeaders.Connection.Add("keep-alive");

現(xiàn)在終于可以收官了。但是肯定不完美,分享的只是解決問題的過程。

到此這篇關(guān)于C#中HttpClient使用注意(預(yù)熱與長連接)的文章就介紹到這了,更多相關(guān)C# HttpClient內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • WPF如何自定義TabControl控件樣式示例詳解

    WPF如何自定義TabControl控件樣式示例詳解

    這篇文章主要給大家介紹了關(guān)于WPF如何自定義TabControl控件樣式的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧。
    2018-04-04
  • C#實現(xiàn)拼手氣紅包算法

    C#實現(xiàn)拼手氣紅包算法

    這篇文章主要為大家詳細介紹了C#實現(xiàn)拼手氣紅包算法,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-09-09
  • 使用C# CefSharp Python采集某網(wǎng)站簡歷并且自動發(fā)送邀請短信的方法

    使用C# CefSharp Python采集某網(wǎng)站簡歷并且自動發(fā)送邀請短信的方法

    這篇文章主要給大家介紹了關(guān)于如何使用C# CefSharp Python采集某網(wǎng)站簡歷并且自動發(fā)送邀請短信的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面來一起看看吧
    2019-03-03
  • C#實現(xiàn)自定義動畫鼠標的示例詳解

    C#實現(xiàn)自定義動畫鼠標的示例詳解

    這篇文章主要為大家詳細介紹了如何利用C#實現(xiàn)自定義動畫鼠標效果,文中的示例代碼講解詳細,對我們學習C#有一定的幫助,感興趣的小伙伴可以跟隨小編一起了解一下
    2022-12-12
  • C#調(diào)用C++的dll兩種實現(xiàn)方式(托管與非托管)

    C#調(diào)用C++的dll兩種實現(xiàn)方式(托管與非托管)

    這篇文章主要介紹了C#調(diào)用C++的dll兩種實現(xiàn)方式(托管與非托管),具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-08-08
  • C#隊列Queue多線程用法實例

    C#隊列Queue多線程用法實例

    這篇文章主要介紹了C#隊列Queue多線程用法,實例分析了隊列的相關(guān)使用技巧,需要的朋友可以參考下
    2015-05-05
  • C#生成本地配置文件的實現(xiàn)示例

    C#生成本地配置文件的實現(xiàn)示例

    本文將介紹如何使用C#語言生成本地配置文件,以便為應(yīng)用程序提供靈活的配置選項,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2024-01-01
  • Unity3D使用陀螺儀控制節(jié)點旋轉(zhuǎn)

    Unity3D使用陀螺儀控制節(jié)點旋轉(zhuǎn)

    這篇文章主要為大家詳細介紹了Unity3D使用陀螺儀控制節(jié)點旋轉(zhuǎn),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-11-11
  • 在類庫或winform項目中打開另一個winform項目窗體的方法

    在類庫或winform項目中打開另一個winform項目窗體的方法

    這篇文章主要介紹了在類庫或winform項目中打開另一個winform項目窗體的方法,可以實現(xiàn)Winform項目間窗體的調(diào)用,在進行Winform項目開發(fā)中非常具有實用價值,需要的朋友可以參考下
    2014-11-11
  • C#實現(xiàn)對AES加密和解密的方法

    C#實現(xiàn)對AES加密和解密的方法

    C#實現(xiàn)對AES加密和解密的方法,需要的朋友可以參考一下
    2013-04-04

最新評論