async/await
내 웹 API 프로젝트에서 ASP.NET 의 기능을 사용하려고합니다 . 내 웹 API 서비스의 성능에 어떤 차이가 있는지 잘 모르겠습니다. 내 응용 프로그램의 워크 플로 및 샘플 코드를 아래에서 찾으십시오.
작업 흐름 :
UI Application → Web API endpoint (controller) → Web API 서비스 레이어에서 메서드 호출 → 다른 외부 웹 서비스 호출. (여기에 DB 상호 작용 등이 있습니다.)
제어 장치:
public async Task<IHttpActionResult> GetCountries()
{
var allCountrys = await CountryDataService.ReturnAllCountries();
if (allCountrys.Success)
{
return Ok(allCountrys.Domain);
}
return InternalServerError();
}
서비스 계층 :
public Task<BackOfficeResponse<List<Country>>> ReturnAllCountries()
{
var response = _service.Process<List<Country>>(BackOfficeEndpoint.CountryEndpoint, "returnCountries");
return Task.FromResult(response);
}
위의 코드를 테스트하고 작동 중입니다. 그러나 그것이 올바른 사용법인지 확실하지 않습니다 async/await
. 여러분의 생각을 공유 해주세요.
답변
API의 성능에 어떤 차이가 있는지 잘 모르겠습니다.
서버 측에서 비동기 코드의 주요 이점은 확장 성 입니다. 마술처럼 요청이 더 빠르게 실행되지는 않습니다. ASP.NET 에 대한async
내 기사에서async
몇 가지 “사용해야 하는가 “고려 사항을 다룹니다 .
사용 사례 (다른 API 호출)가 비동기 코드에 적합하다고 생각합니다. “비동기”가 “더 빠름”을 의미하지는 않는다는 점을 명심하십시오. 가장 좋은 방법은 먼저 UI를 반응 형 및 비동기식으로 만드는 것입니다 . 이렇게하면 앱 이 약간 느려도 더 빠르게 느껴 집니다.
코드가 진행되는 한 이것은 비동기가 아닙니다.
public Task<BackOfficeResponse<List<Country>>> ReturnAllCountries()
{
var response = _service.Process<List<Country>>(BackOfficeEndpoint.CountryEndpoint, "returnCountries");
return Task.FromResult(response);
}
다음과 같은 확장 성 이점을 얻으려면 진정한 비동기 구현이 필요합니다 async
.
public async Task<BackOfficeResponse<List<Country>>> ReturnAllCountriesAsync()
{
return await _service.ProcessAsync<List<Country>>(BackOfficeEndpoint.CountryEndpoint, "returnCountries");
}
또는 (이 메서드의 논리가 실제로 통과 일 경우) :
public Task<BackOfficeResponse<List<Country>>> ReturnAllCountriesAsync()
{
return _service.ProcessAsync<List<Country>>(BackOfficeEndpoint.CountryEndpoint, "returnCountries");
}
이와 같이 “외부”보다 “내부”에서 작업하는 것이 더 쉽습니다. 즉, 비동기 컨트롤러 작업으로 시작하지 말고 다운 스트림 메서드를 비동기로 강제 설정하십시오. 대신 자연스러운 비동기 작업 (외부 API 호출, 데이터베이스 쿼리 등)을 식별하고 가장 낮은 수준에서 먼저 비동기 작업을 만듭니다 ( Service.ProcessAsync
). 그런 다음 async
마지막 단계로 컨트롤러 작업을 비동기식으로 만들어서 조금씩 흐르게하십시오.
Task.Run
이 시나리오 에서는 어떤 상황에서도 사용해서는 안됩니다 .
답변
정확하지만 유용하지 않을 수 있습니다.
기다릴 것이 없으므로 (비동기 적으로 작동 할 수있는 차단 API에 대한 호출이 없음) 비동기 작업 (오버 헤드가 있음)을 추적하는 구조를 설정 한 다음 해당 기능을 사용하지 않습니다.
예를 들어 서비스 계층이 비동기 호출을 지원하는 Entity Framework로 DB 작업을 수행하는 경우 :
public Task<BackOfficeResponse<List<Country>>> ReturnAllCountries()
{
using (db = myDBContext.Get()) {
var list = await db.Countries.Where(condition).ToListAsync();
return list;
}
}
db가 쿼리되는 동안 작업자 스레드가 다른 작업을 수행하도록 허용하여 다른 요청을 처리 할 수 있습니다.
Await는 완전히 내려 가야하는 경향이 있습니다. 기존 시스템에 개조하는 것은 매우 어렵습니다.
답변
동기 메서드 를 실행하는 동안 요청 스레드가 차단되므로 비동기 / 대기 효과를 효과적으로 활용하지 못합니다.ReturnAllCountries()
요청을 처리하기 위해 할당 된 스레드는 ReturnAllCountries()
작동 하는 동안 유휴 상태로 대기 합니다.
ReturnAllCountries()
비동기식으로 구현할 수 있다면 확장 성 이점을 얻을 수 있습니다. 스레드 ReturnAllCountries()
가 실행 되는 동안 다른 요청을 처리하기 위해 .NET 스레드 풀로 다시 해제 될 수 있기 때문 입니다. 이렇게하면 스레드를보다 효율적으로 활용하여 서비스의 처리량을 높일 수 있습니다.
답변
서비스 계층을 다음과 같이 변경합니다.
public Task<BackOfficeResponse<List<Country>>> ReturnAllCountries()
{
return Task.Run(() =>
{
return _service.Process<List<Country>>(BackOfficeEndpoint.CountryEndpoint, "returnCountries");
}
}
당신이 그것을 가지고 있기 때문에, 당신은 여전히 당신의 _service.Process
호출을 동 기적으로 실행 하고 있으며 그것을 기다리는 것으로부터 거의 또는 전혀 이익을 얻지 못합니다.
이 접근 방식을 사용하면 잠재적으로 느린 호출을에서 래핑하고 Task
시작하고 대기 하도록 반환합니다. 이제 Task
.