私はパーティーに遅れていますが、このトリッキーなトピックに関する学習の旅はここにあります。
1. HttpClientの再利用に関する公式の支持者はどこにありますか?
つまり、HttpClientの再利用が意図されて
おり、そうすることが重要である場合、そのような支持者は、多くの「高度なトピック」、「パフォーマンス(アンチ)パターン」、または他のブログ投稿に隠されるのではなく、独自のAPIドキュメントに文書化される方がよい。さもなければ、新しい学習者は手遅れになる前にどのようにそれを知ることになっていますか?
現在(2018年5月)、「c#httpclient」をグーグルで検索したときの最初の検索結果は、MSDNのこのAPIリファレンスページを指していますが、その意図はまったく言及されていません。さて、初心者向けのレッスン1は、MSDNヘルプページの見出しの直後にある「その他のバージョン」リンクをクリックすることです。おそらく「現在のバージョン」へのリンクがあります。このHttpClientの場合、意図説明を含む最新のドキュメントが表示さ
れます。
私はどちらかの正しいドキュメントページを見つけられませんでした、このトピックに新しいだった多くの開発者を疑う、この知識が広く普及していない理由です、そして、彼らはそれを見つけたとき、人々は驚いた
後に、おそらく、ハードな方法で。
2.(誤?)の概念 using
IDisposable
これは少しトピックから外れていますが、指摘する価値はありますが、前述のブログ投稿で、インターフェイスがパターンを使用する傾向があり、問題につながる傾向があると非難するHttpClient
のは偶然ではありません。IDisposable
using (var client = new HttpClient()) {...}
これは、「IDisposableオブジェクトは短命であると予想される」という暗黙の(誤解?)概念に
帰着すると考えています。
ただし、このスタイルでコードを記述すると、確かに短命のように見えますが:
using (var foo = new SomeDisposableObject())
{
...
}
IDisposableの公式ドキュメントで
は、IDisposable
オブジェクトが短命である必要があるとは決して言及していません。定義上、IDisposableは、管理されていないリソースを解放できるメカニズムにすぎません。これ以上何もない。その意味では、あなたは最終的に処分をトリガーすることが期待されていますが、それはあなたが短命の方法でそうすることを必要としません。
したがって、実際のオブジェクトのライフサイクル要件に基づいて、いつ廃棄をトリガーするかを適切に選択するのがあなたの仕事です。IDisposableを長期間使用することを妨げるものは何もありません。
using System;
namespace HelloWorld
{
class Hello
{
static void Main()
{
Console.WriteLine("Hello World!");
using (var client = new HttpClient())
{
for (...) { ... } // A really long loop
// Or you may even somehow start a daemon here
}
// Keep the console window open in debug mode.
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}
}
この新しい理解により、今度はそのブログ投稿を再確認し、「修正」がHttpClient
一度初期化されますが、破棄しないことを明確に確認できます。そのため、netstat出力から、接続はESTABLISHED状態のままであり、適切に閉じられていません。閉じられている場合、その状態は代わりにTIME_WAITになります。実際には、プログラム全体の終了後に開いている接続を1つだけリークすることは大したことではありません。修正後もブログの投稿者はパフォーマンスの向上を確認できます。それでも、IDisposableを非難し、それを破棄しないことを選択することは概念的に正しくありません。
3. HttpClientを静的プロパティに入れる必要がありますか、それともシングルトンとして入れる必要がありますか?
前のセクションの理解に基づいて、ここでの答えが明らかになると思います:「必ずしもではない」。HttpClientを再利用し、(理想的には)最終的に破棄する限り、コードの編成方法に大きく依存します。
陽気に、現在の公式文書の備考セクションの例でさえ、
それを厳密に正しくしていません。破棄されない静的HttpClientプロパティを含む「GoodController」クラスを定義します。これは、
「例」セクションの別の例が強調している「disposeを呼び出す必要があります...アプリがリソースをリークしないようにする」ことに反します。
最後に、シングルトンには独自の課題がないわけではありません。
「グローバル変数は良いアイデアだと思う人は何人いますか?誰もいません。
シングルトンは良いアイデアだと思う人は何人いますか?少し。
何が得られますか?シングルトンはグローバル変数の集まりです。」
-この刺激的な講演「グローバルステートアンドシングルトン」からの引用
PS:SqlConnection
これは現在のQ&Aとは無関係ですが、おそらく知っておくと便利です。SqlConnectionの使用パターンは異なります。あなたは、SqlConnectionオブジェクトを再利用する必要はありません、それはその接続プールより良い、そのように処理しますので、。
違いは、実装アプローチが原因です。各HttpClientインスタンスは、独自の接続プール(ここから引用
)を使用します。しかし、SqlConnectionオブジェクト自体はによると、中央の接続プールによって管理され、この。
また、HttpClientの場合と同じように、SqlConnectionを破棄する必要があります。