HttpClient SendAsync memblokir utas utama
Saya telah menulis aplikasi winforms kecil yang mengirimkan permintaan http ke setiap alamat ip dalam jaringan lokal saya untuk menemukan perangkat tertentu milik saya. Pada subnet mask saya itulah 512 alamat. Saya telah menulis ini menggunakan backGroundWorker tetapi saya ingin mencoba httpClient dan pola Async / Await untuk mencapai hal yang sama. Kode di bawah ini menggunakan satu contoh httpClient dan saya menunggu sampai semua permintaan selesai. Masalah ini adalah utas utama diblokir. Saya tahu ini karena saya memiliki kotak gambar + memuat gif dan tidak dianimasikan secara seragam. Saya menempatkan metode GetAsync di Task.Run seperti yang disarankan di sini tetapi itu juga tidak berhasil.
private async void button1_Click(object sender, EventArgs e)
{
var addresses = networkUtils.generateIPRange..
await MakeMultipleHttpRequests(addresses);
}
public async Task MakeMultipleHttpRequests(IPAddress[] addresses)
{
List<Task<HttpResponseMessage>> httpTasks = new List<Task<HttpResponseMessage>>();
foreach (var address in addresses)
{
Task<HttpResponseMessage> response = MakeHttpGetRequest(address.ToString());
httpTasks.Add(response);
}
try
{
if (httpTasks.ToArray().Length != 0)
{
await Task.WhenAll(httpTasks.ToArray());
}
}
catch (Exception ex)
{
Console.WriteLine("\thttp tasks did not complete Exception : {0}", ex.Message);
}
}
private async Task<HttpResponseMessage> MakeHttpGetRequest(string address)
{
var url = string.Format("http://{0}/getStatus", address);
var cts = new System.Threading.CancellationTokenSource();
cts.CancelAfter(TimeSpan.FromSeconds(10));
HttpResponseMessage response = null;
var request = new HttpRequestMessage(HttpMethod.Get, url);
response = await httpClient.SendAsync(request, cts.Token);
return response;
}
Saya telah membaca masalah serupa di sini tetapi utas Gui saya tidak banyak membantu. Saya telah membaca di sini bahwa saya mungkin kehabisan utas. Apakah ini masalahnya, bagaimana cara mengatasinya? Saya tahu itu Send Async karena jika saya mengganti kode dengan tugas sederhana di bawah ini tidak ada pemblokiran.
await Task.Run(() =>
{
Thread.Sleep(1000);
});
Jawaban
Jadi salah satu masalah di sini adalah Anda membuat 500+ tugas satu demi satu secara berurutan dengan cepat dengan batas waktu yang ditetapkan di luar pembuatan tugas.
Hanya karena Anda meminta untuk menjalankan 500+ tugas, tidak berarti 500+ tugas akan dijalankan pada waktu yang sama. Mereka mengantri dan berjalan ketika penjadwal menganggap itu mungkin.
Anda menyetel waktu tunggu pada saat pembuatan 10 detik. Tapi mereka bisa duduk di penjadwal selama 10 detik bahkan sebelum dieksekusi.
Anda ingin permintaan Http Anda ke waktu tunggu secara organik, Anda dapat melakukannya seperti ini saat Anda membuat HttpClient:
private static readonly HttpClient _httpClient = new HttpClient
{
Timeout = TimeSpan.FromSeconds(10)
};
Jadi, dengan memindahkan waktu tunggu ke HttpClient, metode Anda sekarang akan terlihat seperti ini:
private static Task<HttpResponseMessage> MakeHttpGetRequest(string address)
{
return _httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Get, new UriBuilder
{
Host = address,
Path = "getStatus"
}.Uri));
}
Coba gunakan metode itu dan lihat apakah itu memperbaiki masalah penguncian Anda dalam mode Debug.
Sejauh masalah yang Anda sedang mengalami: Ini mengunci karena Anda berada dalam mode Debug dan debugger sedang mencoba untuk mengatakan "hey, Anda punya pengecualian" 500 kali semua pada waktu yang sama karena mereka semua melahirkan pada waktu yang sama . Jalankan dalam mode Rilis dan lihat apakah masih terkunci.
Apa yang akan saya pertimbangkan untuk dilakukan adalah menyusun operasi Anda. Lakukan 20, lalu tunggu sampai 20 selesai, lakukan 20 lagi, begitu seterusnya.
Jika Anda ingin melihat cara yang apik dalam mengelompokkan tugas, beri tahu saya dan saya akan dengan senang hati menunjukkannya kepada Anda.
Di .NET Framework, jumlah koneksi ke server dikontrol oleh Kelas ServicePointManager .
Untuk klien, batas koneksi default adalah 2 pada proses klien.
Tidak peduli berapa banyak pemanggilan HttpClient.SendAsync yang Anda lakukan, hanya 2 yang akan aktif pada waktu yang sama.
Tapi Anda bisa mengatur sendiri koneksinya .
Di .NET Core di sini bukanlah konsep manajer titik layanan dan batas default yang setara adalah int.MaxValue.