Saya terlambat ke pesta, tapi inilah perjalanan belajar saya tentang topik rumit ini.
1. Di mana kami dapat menemukan advokat resmi untuk menggunakan kembali HttpClient?
Maksud saya, jika menggunakan kembali HttpClient dimaksudkan
dan melakukannya adalah penting , advokat seperti itu lebih baik didokumentasikan dalam dokumentasi API-nya sendiri, daripada disembunyikan di banyak "Topik Lanjut", "Pola kinerja (anti)" atau posting blog lainnya di luar sana . Kalau tidak, bagaimana mungkin seorang pelajar baru mengetahuinya sebelum terlambat?
Sampai sekarang (Mei 2018), hasil pencarian pertama ketika googling "c # httpclient" menunjuk ke halaman referensi API ini di MSDN , yang tidak menyebutkan maksud itu sama sekali. Nah, pelajaran 1 di sini untuk pemula adalah, selalu klik tautan "Versi Lain" tepat setelah judul halaman bantuan MSDN, Anda mungkin akan menemukan tautan ke "versi saat ini" di sana. Dalam kasus HttpClient ini, ini akan membawa Anda ke dokumen terbaru di
sini yang berisi uraian niat tersebut .
Saya curiga banyak pengembang yang baru mengenal topik ini juga tidak menemukan halaman dokumentasi yang benar, itu sebabnya pengetahuan ini tidak tersebar luas, dan orang-orang terkejut ketika mereka menemukannya
nanti , mungkin dengan cara yang sulit .
2. Konsepsi (salah?) Dari using
IDisposable
Satu ini sedikit di luar topik tapi masih layak menunjuk bahwa, itu bukan kebetulan melihat orang-orang pada mereka posting blog tersebut menyalahkan bagaimana HttpClient
's IDisposable
antarmuka membuat mereka cenderung menggunakan using (var client = new HttpClient()) {...}
pola dan kemudian menyebabkan masalah.
Saya percaya bahwa konsepsi tak terucap (salah?):
"Sebuah objek IDisposable diharapkan berumur pendek" .
NAMUN, sementara itu terlihat seperti hal yang berumur pendek ketika kita menulis kode dengan gaya ini:
using (var foo = new SomeDisposableObject())
{
...
}
yang dokumentasi resmi pada IDisposable
tidak pernah menyebutkan IDisposable
benda harus berumur pendek. Menurut definisi, IDisposable hanyalah sebuah mekanisme untuk memungkinkan Anda melepaskan sumber daya yang tidak dikelola. Tidak ada lagi. Dalam hal itu, Anda HARUS pada akhirnya memicu pembuangan, tetapi itu tidak mengharuskan Anda untuk melakukannya dalam waktu singkat.
Karena itu, tugas Anda adalah memilih dengan tepat kapan akan memicu pembuangan, berdasarkan kebutuhan siklus hidup objek nyata Anda. Tidak ada yang menghentikan Anda menggunakan IDisposable dengan cara yang tahan lama:
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();
}
}
}
Dengan pemahaman baru ini, sekarang kita meninjau kembali posting blog itu , kita dapat dengan jelas melihat bahwa "perbaikan" diinisialisasi HttpClient
sekali tetapi tidak pernah membuangnya, itu sebabnya kita dapat melihat dari output netstatnya bahwa, koneksi tetap pada keadaan ESTABLISHED yang berarti ia memiliki TIDAK ditutup dengan benar. Jika ditutup, kondisinya akan menjadi TIME_WAIT sebagai gantinya. Dalam praktiknya, tidak masalah untuk membocorkan hanya satu koneksi yang terbuka setelah seluruh program Anda berakhir, dan poster blog masih melihat peningkatan kinerja setelah perbaikan; tapi tetap saja, secara konseptual salah untuk menyalahkan IDisposable dan memilih untuk TIDAK membuangnya.
3. Apakah kita harus meletakkan HttpClient ke properti statis, atau bahkan menjadikannya sebagai singleton?
Berdasarkan pemahaman dari bagian sebelumnya, saya pikir jawabannya di sini menjadi jelas: "belum tentu". Ini benar-benar tergantung pada bagaimana Anda mengatur kode Anda, selama Anda menggunakan kembali HttpClient AND (idealnya) buang pada akhirnya.
Meriah, bahkan contoh di bagian
Keterangan dari dokumen resmi saat ini
tidak benar. Ini mendefinisikan kelas "GoodController", yang mengandung properti HttpClient statis yang tidak akan dibuang; yang tidak mematuhi apa contoh lain di bagian Contoh
menekankan: "perlu memanggil buang ... sehingga aplikasi tidak membocorkan sumber daya".
Dan terakhir, singleton bukan tanpa tantangannya sendiri.
"Berapa banyak orang berpikir variabel global adalah ide yang bagus? Tidak ada.
Berapa banyak orang berpikir bahwa singleton adalah ide yang bagus? Beberapa.
Apa yang menyebabkannya? Lajang hanya sekelompok variabel global. "
- Dikutip dari ceramah yang menginspirasi ini, "Negara Global dan Lajang"
PS: Koneksi Sql
Yang ini tidak relevan dengan T&J saat ini, tetapi ini mungkin baik untuk diketahui. Pola penggunaan SqlConnection berbeda. Anda TIDAK perlu menggunakan kembali SqlConnection , karena ia akan menangani kelompok koneksi dengan lebih baik.
Perbedaan tersebut disebabkan oleh pendekatan implementasi mereka. Setiap instance HttpClient menggunakan kumpulan koneksi sendiri (dikutip dari
sini ); tetapi SqlConnection sendiri dikelola oleh pool koneksi sentral, menurut ini .
Dan Anda masih perlu membuang SqlConnection, sama seperti yang seharusnya Anda lakukan untuk HttpClient.