最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

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

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

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

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

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

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

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

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

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

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

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

在之前的測(cè)試中,我們每次用HttpClient發(fā)請(qǐng)求時(shí),都是新建一個(gè)HttpClient實(shí)例,用完就對(duì)它進(jìn)行Dispose,代碼如下:

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

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

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

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

然后測(cè)試一下請(qǐng)求響應(yīng)時(shí)間:

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

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

通過Wireshak抓包也驗(yàn)證了長(zhǎng)連接的效果:

Wireshak抓包

這時(shí),你

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();
? ? }
}

也許會(huì)產(chǎn)生這樣的疑問:將HttpClient聲明為靜態(tài)變量,會(huì)不會(huì)存在線程安全問題?我們當(dāng)時(shí)也有這樣的疑問,后來在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的問題是不是可以完美收官了?。。。稍等,還有一個(gè)問題。

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

所以,我們還要給HttpClient增加一個(gè)Connection:keep-alive的請(qǐng)求頭,代碼如下:

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

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

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

相關(guān)文章

  • C#不改變圖像長(zhǎng)寬比例調(diào)整圖像大小方式

    C#不改變圖像長(zhǎng)寬比例調(diào)整圖像大小方式

    文章介紹了在UI顯示圖片時(shí),當(dāng)容器大小固定而圖片尺寸大于容器時(shí),可以通過編碼計(jì)算長(zhǎng)寬來重繪圖像,以確保圖像的長(zhǎng)寬比例不變,C#代碼示例展示了如何在Winform前端實(shí)現(xiàn)這一功能
    2025-01-01
  • C#中值類型和引用類型的使用與比較

    C#中值類型和引用類型的使用與比較

    在C#中,數(shù)據(jù)類型分為值類型和引用類型兩種,引用類型變量存儲(chǔ)的是數(shù)據(jù)的引用,而值類型變量直接存儲(chǔ)數(shù)據(jù),下面小編就來和大家講講這二者的使用與區(qū)別吧
    2023-07-07
  • C#通過重寫Panel改變邊框顏色與寬度的方法

    C#通過重寫Panel改變邊框顏色與寬度的方法

    這篇文章主要介紹了C#通過重寫Panel改變邊框顏色與寬度的方法,涉及C#針對(duì)Panel控件的重寫與屬性設(shè)置技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-08-08
  • 詳解C#如何提取PDF文檔中的圖片

    詳解C#如何提取PDF文檔中的圖片

    提取圖片可以將這些圖像資源進(jìn)行單獨(dú)保存,方便后續(xù)在不同的項(xiàng)目中使用,下面我們就來看看如何使用C#通過代碼從PDF文檔中提取圖片吧
    2025-04-04
  • 詳解c# 中的DateTime

    詳解c# 中的DateTime

    這篇文章主要介紹了c# 中的DateTime的相關(guān)資料,文中講解非常細(xì)致,代碼幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下
    2020-07-07
  • WPF如何實(shí)現(xiàn)日期范圍選擇器

    WPF如何實(shí)現(xiàn)日期范圍選擇器

    這篇文章主要為大家詳細(xì)介紹了WPF如何實(shí)現(xiàn)日期范圍選擇器,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2024-11-11
  • C# 通過NI-VISA操作Tektronix TBS 2000B系列示波器的實(shí)現(xiàn)步驟

    C# 通過NI-VISA操作Tektronix TBS 2000B系列示波器的實(shí)現(xiàn)步驟

    這篇文章主要介紹了C# 通過NI-VISA操作Tektronix TBS 2000B系列示波器的實(shí)現(xiàn)步驟,幫助大家更好的理解和學(xué)習(xí)使用c#,感興趣的朋友可以了解下
    2021-02-02
  • 使用C#實(shí)現(xiàn)解析Excel公式

    使用C#實(shí)現(xiàn)解析Excel公式

    在日常工作中,我們經(jīng)常需要在Excel中使用公式對(duì)表中數(shù)據(jù)進(jìn)行計(jì)算和分析,所以本文小編主要來和大家介紹一下如何在C#中實(shí)現(xiàn)解析Excel公式,感興趣的可以了解下
    2024-02-02
  • C# 并行和多線程編程——并行集合和PLinq

    C# 并行和多線程編程——并行集合和PLinq

    這篇文章主要介紹了C# 并行和多線程編程的相關(guān)資料,幫助大家更好的理解和學(xué)習(xí)使用c#,感興趣的朋友可以了解下
    2021-02-02
  • C# 封裝HtmlHelper組件:BootstrapHelper

    C# 封裝HtmlHelper組件:BootstrapHelper

    這篇文章主要介紹了C# 封裝HtmlHelper組件之BootstrapHelper 的相關(guān)資料,需要的朋友可以參考下
    2016-08-08

最新評(píng)論

兴山县| 外汇| 册亨县| 兰考县| 台中县| 清原| 来安县| 楚雄市| 霞浦县| 昌乐县| 湛江市| 万安县| 修武县| 海淀区| 谢通门县| 财经| 澄江县| 宿迁市| 岗巴县| 来安县| 西平县| 黔西| 比如县| 南雄市| 精河县| 寿阳县| 成都市| 崇信县| 新郑市| 得荣县| 吴旗县| 阜新市| 安新县| 怀柔区| 淳化县| 瑞丽市| 苗栗县| 治多县| 通渭县| 通城县| 临泉县|