HttpClient SendAsync가 메인 스레드를 차단합니다.
내 특정 장치를 찾기 위해 로컬 네트워크 내의 모든 IP 주소에 http 요청을 보내는 작은 winforms 응용 프로그램을 작성했습니다. 내 특정 서브넷 마스크에서 512 개 주소입니다. 나는 backGroundWorker를 사용하여 이것을 작성했지만 httpClient와 Async / Await 패턴을 사용해 똑같은 결과를 얻고 싶었습니다. 아래 코드는 httpClient의 단일 인스턴스를 사용하며 모든 요청이 완료 될 때까지 기다립니다. 이 문제는 주 스레드가 차단된다는 것입니다. 나는 picturebox + 로딩 gif가 있고 균일하게 애니메이션되지 않기 때문에 이것을 알고 있습니다. 여기에 제안 된대로 Task.Run에 GetAsync 메서드를 넣었 지만 작동하지 않았습니다.
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;
}
나는 여기 에서 비슷한 문제를 읽었 지만 내 GUI 스레드가 많이하지 않습니다. 나는 여기 에서 스레드가 부족할 수 있다고 읽었습니다 . 이것이 문제입니까? 어떻게 해결할 수 있습니까? 아래의 간단한 작업으로 코드를 바꾸면 차단이 없기 때문에 Send Async를 알고 있습니다.
await Task.Run(() =>
{
Thread.Sleep(1000);
});
답변
따라서 여기서 문제 중 하나는 작업 생성 외부에 시간 제한을 설정하여 500 개 이상의 작업을 연속적으로 빠르게 생성한다는 것입니다.
500 개 이상의 작업을 실행하도록 요청했다고해서 500 개 이상의 작업이 모두 동시에 실행되는 것은 아닙니다. 스케줄러가 가능하다고 판단 할 때 대기열에 추가되고 실행됩니다.
10 초 생성시 제한 시간을 설정합니다. 그러나 그들은 실행되기 전에 10 초 동안 스케줄러에 앉아있을 수 있습니다.
Http 요청이 유기적으로 시간 초과되도록하려면 HttpClient
다음 을 만들 때 다음과 같이 할 수 있습니다 .
private static readonly HttpClient _httpClient = new HttpClient
{
Timeout = TimeSpan.FromSeconds(10)
};
따라서 시간 제한을로 이동하면 HttpClient
이제 메서드가 다음과 같이 보일 것입니다.
private static Task<HttpResponseMessage> MakeHttpGetRequest(string address)
{
return _httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Get, new UriBuilder
{
Host = address,
Path = "getStatus"
}.Uri));
}
이 방법을 사용 해보고 디버그 모드에서 잠금 문제가 개선되는지 확인하십시오.
문제 가있는 한 : 디버그 모드에 있고 디버거가 모두 동시에 생성 되었기 때문에 "예외가 생겼습니다"라고 동시에 500 번 말하려고 했기 때문에 잠겼 습니다 . 릴리스 모드에서 실행하고 여전히 잠겨 있는지 확인하십시오.
내가 고려할 것은 작업을 일괄 처리하는 것입니다. 20 번을 한 다음 20 번이 끝날 때까지 기다렸다가 20 번 더 작업하는 식입니다.
작업을 매끄럽게 일괄 처리하는 방법을보고 싶다면 알려주세요. 기꺼이 보여 드리겠습니다.
.NET Framework에서 서버에 대한 연결 수는 ServicePointManager 클래스에 의해 제어됩니다 .
클라이언트의 경우 기본 연결 제한 은 클라이언트 프로세스에서 2 입니다.
수행하는 HttpClient.SendAsync 호출의 수에 관계없이 동시에 2 개만 활성화됩니다.
그러나 연결을 직접 관리 할 수 있습니다 .
.NET Core에서는 여기에 서비스 지점 관리자의 개념이 없으며 이에 상응하는 기본 제한은 int.MaxValue입니다.