언제 ASP.NET MVC에서 비동기 컨트롤러를 사용해야합니까?


216

ASP.NET MVC에서 비동기 작업을 사용하는 데 약간의 문제가 있습니다. 언제 내 앱의 성능을 개선합니까? 하지 ?

  1. ASP.NET MVC의 모든 곳에서 비동기 작업을 사용하는 것이 좋습니까?
  2. 대기 가능한 방법과 관련하여 (EF / NHibernate / other ORM을 통해) 데이터베이스를 쿼리 할 때 async / await 키워드를 사용해야합니까?
  3. 하나의 단일 조치 메소드 에서 await 키워드를 사용하여 데이터베이스를 비동기 적으로 쿼리 할 수있는 횟수는 몇 번 입니까?

답변:


109

비동기 조치 메소드는 조치가 여러 개의 독립적 인 장기 실행 조작을 수행해야 할 때 유용합니다.

AsyncController 클래스의 일반적인 용도는 오래 실행되는 웹 서비스 호출입니다.

데이터베이스 호출이 비동기식이어야합니까?

IIS 스레드 풀은 종종 데이터베이스 서버보다 더 많은 동시 차단 요청을 처리 할 수 ​​있습니다. 데이터베이스가 병목 상태 인 경우 비동기 호출은 데이터베이스 응답 속도를 높이 지 않습니다. 제한 메커니즘이 없으면 비동기 호출을 사용하여 더 많은 작업을 압도적 데이터베이스 서버로 효율적으로 디스패치하면 데이터베이스에 대한 부담이 더 커집니다. DB에 병목 현상이 발생하면 비동기 호출이 마법의 총알이 아닙니다.

당신 12를 봐야합니다 참조를

@PanagiotisKanavos 의견에서 파생되었습니다.

또한 비동기는 병렬을 의미하지 않습니다. 비동기 실행은 복잡한 스레드 나 성능 비용없이 소중한 스레드 풀 스레드가 외부 리소스를 차단하지 않도록합니다. 이는 동일한 IIS 시스템이 더 많은 동시 요청을 처리 할 수 ​​있다는 것을 의미합니다.

또한 차단 호출은 CPU 집약적 스핀 웨이트로 시작해야합니다. 스트레스 시간 동안 통화를 차단하면 지연이 지연되고 앱 풀이 재활용됩니다. 비동기 호출은 단순히 이것을 피하십시오


27
비동기, IIS 및 데이터베이스와 관련하여 블로그 게시물은 매우 오래되었으며 여기에 그려진 결론은 잘못되었습니다. IIS는 데이터베이스보다 훨씬 더 큰 부하 를 서버에 가져야하며 스레드 풀 스레드는 제한되며 긴 요청 큐는 500으로 이어질 수 있습니다. IO를 기다리는 동안 스레드를 해제하는 것은 유리합니다. 링크조차도 OP가 요구 한 것에 관한 것이 아닙니다 . 실제로 동일한 저자는 가능한 한 비동기 DB 방법 을 사용해야한다고 썼다
Panagiotis Kanavos

30
또한 비동기는 병렬을 의미하지 않습니다. 비동기 실행은 복잡한 스레드 나 성능 비용없이 소중한 스레드 풀 스레드가 외부 리소스를 차단하지 않도록합니다. 이는 동일한 IIS 시스템더 많은 동시 요청을 처리 할 수 ​​있다는 것을 의미 합니다 .
파나지오티스 카나 보스

5
또한 차단 호출은 CPU 집약적 스핀 웨이트로 시작해야합니다. 스트레스 시간 동안 통화를 차단하면 지연이 지연되고 앱 풀이 재활용됩니다. 비동기식 호출은 단순히 이것을 피합니다
Panagiotis Kanavos

1
이것이 대답으로 받아 들여지고 대부분의 사람들이 맨 위에 있기 때문에 실행 시간과 병렬 실행과 관련하여 두 번째 첫 번째 단락을 제거하는 것이 좋습니다. 나는 메모가 마지막에있다 실현,하지만 되어 매우 오해의 소지가.
Rob

1
비동기 실행은 구현의 맨 아래까지 진정으로 비 동기화되는 경우에만 스레드를 해제하고 일부 콜백 메커니즘을 사용하여 준비를 신호하고 컨텍스트를 전환하고 결과를 처리하기 위해 새 스레드를 스핀 업합니다. 따라서이 컨텍스트 전환 / 새 스레드 생성이 단일 스레드의 결과를 기다리는 것보다 더 효율적인 경우는 무엇입니까? 어쨌든 오래 실행되는 웹 서비스 호출은 나쁜 생각입니다. 나는 신뢰할 수있는 백그라운드 서비스로 오프로드하고 클라이언트가 몇 분, 몇 시간 또는 며칠이 걸릴 수있는 결과를 확인하도록하는 것을 선호합니다.
JustAMartin

229

당신은 내 찾을 수 있습니다 도움이 주제에 대한 MSDN 문서를 ; 이 기사에서는 ASP.NET에서 사용 하는 방법 뿐만 아니라 ASP.NET에서 언제 사용 해야하는지 설명하는 많은 공간을 차지했습니다 .asyncasync

ASP.NET MVC에서 비동기 작업을 사용하는 데 약간의 문제가 있습니다. 앱 성능을 향상시킬 때와 그렇지 않을 때

먼저 async/ await스레드해제하는 것임을 이해하십시오 . GUI 응용 프로그램에서는 주로 GUI 스레드를 해제 하여 사용자 경험을 향상시키는 것입니다. 서버 응용 프로그램 (ASP.NET MVC 포함)에서 주로 요청 스레드를 해제하는 것입니다. 서버가 확장 할 수 있도록 입니다.

특히, 그것은 하지 않습니다 :

  • 개별 요청을 더 빨리 완료하십시오. 실제로, 그들은 완만하게 (완전히 조금씩) 완만하게 될 것이다.
  • 를 누르면 발신자 / 브라우저로 돌아갑니다 await. await브라우저가 아닌 ASP.NET 스레드 풀에만 "수율"이됩니다.

첫 번째 질문은 ASP.NET MVC의 모든 곳에서 비동기 작업을 사용하는 것이 좋습니까?

I / O를 수행하는 모든 곳에서 사용하는 것이 좋습니다. 반드시 그런 것은 아닙니다 도움 (아래 참조).

그러나 CPU 바운드 방법에는 사용하지 않습니다 . 때때로 DEVS은의 혜택을받을 수 있다고 생각 async바로 호출하여Task.Run 는 컨트롤러를 하며 이는 끔찍한 아이디어입니다. 이 코드는 다른 스레드를 사용하여 요청 스레드를 해제하므로 아무런 이점이 없습니다 (실제로 추가 스레드 스위치의 페널티를 받고 있습니다)!

데이터베이스를 쿼리 할 때 (EF / NHibernate / other ORM을 통해) async / await 키워드를 사용해야합니까?

사용 가능한 대기 가능한 방법을 사용할 수 있습니다. 현재 대부분의 주요 플레이어는을 지원 async하지만 그렇지 않은 플레이어 도 있습니다. 귀하의 ORM이를 지원하지 않는 경우 async포장하지 마십시오Task.Run 또는 이와 유사한 것을 (위 참조).

내가 " 사용할 수있다 "고 말했음을 주목하십시오 . 단일 데이터베이스 백엔드로 ASP.NET MVC에 대해 이야기하고 있다면 확장 성 이점을 얻지 못할 것입니다 async. IIS는 단일 SQL Server 인스턴스 (또는 다른 클래식 RDBMS)보다 훨씬 많은 동시 요청을 처리 할 수 ​​있기 때문입니다. 그러나 백엔드는 더 현대적인 경우 - SQL Server 클러스터, 푸른 SQL, NoSQL의 등 -과 백엔드 확장 할 수 있습니다, 그리고 확장 성 병목 현상, IIS입니다 다음 당신이에서 확장 성 혜택을받을 수 있습니다 async.

세 번째 질문-하나의 단일 조치 메소드에서 데이터베이스를 비동기식으로 쿼리하기 위해 대기 키워드를 몇 번 사용할 수 있습니까?

당신이 원하는만큼. 그러나 많은 ORM에는 연결 당 하나의 작업 규칙이 있습니다. 특히 EF는 DbContext 당 단일 작업 만 허용합니다. 작업이 동기식인지 비동기식인지에 관계없이 마찬가지입니다.

또한 백엔드의 확장 성을 다시 염두에 두십시오. 단일 SQL Server 인스턴스를 사용 중이고 IIS가 이미 SQLServer를 전체 용량으로 유지할 수있는 경우 SQLServer에 대한 압력을 두 배로 늘리거나 세 배로 늘려도 전혀 도움이되지 않습니다.


2
@seebiscuit : (적절한 비동기) I / O를 수행 할 때 스레드가 사용되지 않습니다. 좀 더 자세히 설명 하는 블로그 게시물 이 있습니다.
Stephen Cleary

2
IIS와 단일 SQL Server 인스턴스가 몇 개의 요청을 처리 할 수 ​​있습니까? 이 번호를 어떻게 찾을 수 있습니까?
MOD

1
@MOD : 구성 및 하드웨어에 따라 다릅니다. 이 숫자를 찾는 유일한 방법은 자신의 서버에서로드 테스트를 수행하는 것입니다.
Stephen Cleary

1
@Flezcano : CPU에서 완전히 실행되는 메소드. 즉, I / O 또는 차단을 수행하지 않습니다.
Stephen Cleary

1
죄송하지만 선생님은 내가 이해하려고하는이 2 라이너 질문을 수락하지 않을 것입니다. 내가 1000 명의 사용자가 동시에 호출 한 1 개의 웹 API 엔드 포인트가 있으면이 엔드 포인트가 가능할 것입니다. 이 천 가지 요청 각각을 서버에 보내거나 1000 번 요청을 처리하도록 비 동기화해야합니까?
Learning-Overthinker-Confused

21

ASP.NET MVC의 모든 곳에서 비동기 작업을 사용하는 것이 좋습니까?

프로그램에서 평소와 같이, 그것은 의존한다 . 특정 경로를 따라갈 때 항상 상충 관계가 있습니다.

async-await서비스에 대한 동시 요청을 받고 잘 확장 할 수있는 곳에서 빛납니다 . 어떻게 async-await수평 확장에 도움을? 네트워크 호출이나 데이터베이스 히트와 같은 비동기 IO 호출을 동기식 으로 호출하면 실행을 담당하는 현재 스레드가 요청이 완료되기를 기다리는 동안 차단됩니다. 사용할 때async-await , 당신은 IO 호출이 완료되면, 당신의 방법이 off 상태에서 실행을 계속 확인하게하는 당신을위한 상태 머신을 생성하는 프레임 워크를 가능하게한다.

주목해야 할 것은이 상태 머신에는 미묘한 오버 헤드가 있다는 것입니다. 메소드를 비동기 적으로 만든다고해서 더 빨리 실행되는 것은 아니며 , 이는 많은 사람들이 이해하고 이해하는 데 중요한 요소입니다.

사용할 때 고려해야 할 또 다른 사항 async-await비동기식 이라는 사실입니다 . 즉, 비동기식이 전체 통화 스택에 침투하는 것을 볼 수 있습니다. 즉, 동기식 API를 노출하려는 경우 비동기동기화 가 잘 혼합되지 않기 때문에 일정량의 코드를 복제하는 경우가 종종 있습니다.

데이터베이스를 쿼리 할 때 (EF / NHibernate / other ORM을 통해) async / await 키워드를 사용해야합니까?

비동기 IO 호출을 사용하는 경로를 아래로 async-await선택하면 점점 더 현대적인 데이터베이스 공급자가 TAP (Task Asynchronous Pattern)를 구현하는 비동기 메서드를 노출하므로 좋습니다.

ONE 단일 조치 메소드에서 await 키워드를 사용하여 데이터베이스를 비동기 적으로 쿼리 할 수있는 횟수는 몇 번입니까?

데이터베이스 제공자가 지정한 규칙을 따르는 한 원하는만큼. 비동기 호출의 양에는 제한이 없습니다. 서로 독립적이며 동시에 수행 할 수있는 쿼리가있는 경우 각각에 대해 새 작업을 수행 await Task.WhenAll하고 둘 다 완료 될 때까지 사용할 수 있습니다.


2
비동기 DB 호출은 더 빠르게 실행되지 않지만 스레드 풀 스레드가 낭비되지 않기 때문에 동일한 IIS 시스템이 더 많은 요청을 서버에 제공 할 수 있습니다. 또한 차단 호출은 실제로 차단하기 전에 CPU를 많이 사용하는 스핀 대기로 시작하므로 CPU 비용이 절감됩니다. 높은 부하 상황에서이 어려움을 겪고 또는 실패 및 재활용 기계 사이의 차이를 할 수 있습니다
파나지오티스 Kanavos을

@PanagiotisKanavos 내가 아는 한, 내가 말한 내용이 명확하지 않습니까?
유발 이츠 차 코프

1
귀하의 답변에는 IIS 관련 내용이 언급되어 있지 않습니다. 멜트 다운 / 재활용 시나리오는 전체적으로 비동기를 사용하는 주된 이유입니다. 그것을 경험하지 않은 사람은 아마 그 scale out well의미를 이해하지 못할 것입니다 your server won't die under load. 또는 다음과 같은 경우 일 수 있습니다once burned ...
Panagiotis Kanavos 2016 년

7

내 5 센트 :

  1. async/awaitDB 또는 외부 서비스 웹 서비스와 같은 IO 작업을 수행하는 경우에만 사용하십시오 .
  2. 항상 DB에 대한 비동기 호출을 선호하십시오.
  3. DB를 쿼리 할 때마다

추신 : 포인트 1의 경우는 예외이지만 비동기 내부를 잘 이해해야합니다.

추가적인 이점으로, 필요한 경우 몇 개의 IO 호출을 병렬로 수행 할 수 있습니다.

Task task1 = FooAsync(); // launch it, but don't wait for result
Task task2 = BarAsync(); // launch bar; now both foo and bar are running
await Task.WhenAll(task1, task2); // this is better in regard to exception handling
// use task1.Result, task2.Result

6

async작업은 DB 또는 일부 네트워크 바운드 호출에 대한 일부 I / O 작업을 수행하거나 방금 호출 한 DB 또는 네트워크 바운드 호출에서 응답을 받기 전에 요청을 처리하는 스레드가 중단되는 경우에 가장 유용합니다. 함께 사용하는 것이 가장 좋으며 응용 프로그램의 응답 성을 향상시킵니다 (DB 또는 이와 같은 다른 작업을 기다리는 동안 ASP 입력 / 출력 스레드가 중단되기 때문에). 모든 응용 프로그램에서 DB에 대한 많은 호출이 필요할 때마다 항상 훌륭한 방법으로 감싸고 await키워드로 호출했습니다 .


5

아시다시피 MVC는 비동기 컨트롤러를 지원하므로이를 활용해야합니다. 컨트롤러가 긴 작업을 수행하는 경우 (디스크 기반 I / O 또는 다른 원격 서비스에 대한 네트워크 호출 일 수 있음) 요청이 동기 방식으로 처리되면 IIS 스레드는 항상 사용 중입니다. 결과적으로 스레드는 긴 작업이 완료되기를 기다리고 있습니다. 처음 요청 된 작업이 진행되는 동안 다른 요청을 처리하여 더 잘 활용할 수 있습니다. 이는 더 많은 동시 요청을 처리하는 데 도움이됩니다. 웹 서비스는 확장 성이 뛰어나며 C10k 문제에 쉽게 부딪치지 않습니다 . db 쿼리에 async / await를 사용하는 것이 좋습니다. 그리고 당신은 당신이 생각하는만큼 여러 번 사용할 수 있습니다.

훌륭한 조언을 위해 여기 를 살펴보십시오 .


3

내 경험은 오늘날 많은 개발자들이 async/await 들이 컨트롤러의 기본값으로 .

내 제안은 당신이 그것을 도울 것이라는 것을 알고있을 때만 사용하는 것입니다. 입니다.

그 이유는 Stephen Cleary 와 다른 사람들이 이미 언급했듯이 성능 문제를 해결하지 않고 도입 할 수 있으며 특정 시나리오에서만 도움이 될 것입니다.

  • 트래픽이 많은 컨트롤러
  • 확장 가능한 백엔드

2

ASP.NET MVC의 모든 곳에서 비동기 작업을 사용하는 것이 좋습니까?

특히 대량의 데이터 및 계산 작업에 대해 발생하는 작업자 프로세스 수준에서 성능 문제가있는 경우 비동기 방법을 사용할 수있는 모든 위치에서 수행하는 것이 좋습니다. 그렇지 않으면 단위 테스트에 캐스팅이 필요하므로 필요하지 않습니다.

대기 가능한 방법과 관련하여 (EF / NHibernate / other ORM을 통해) 데이터베이스를 쿼리 할 때 async / await 키워드를 사용해야합니까?

예. 작업자 프로세스 수준에서 성능 문제를 피하기 위해 가능한 한 모든 DB 작업에 비동기를 사용하는 것이 좋습니다. EF는 다음과 같은 대부분의 작업에 대해 여러 가지 비동기 대안을 만들었습니다.

.ToListAsync()
.FirstOrDefaultAsync()
.SaveChangesAsync()
.FindAsync()

하나의 단일 조치 메소드에서 await 키워드를 사용하여 데이터베이스를 비동기 적으로 쿼리 할 수있는 횟수는 몇 번입니까?

하늘이 한계입니다


대부분의 웹 응용 프로그램에 대한 비즈니스 논리는 일반적으로 매우 순차적 인 작업이 필요하므로 대부분의 경우 병렬 프로세스간에 점프하는 것은 웹 요청 / 작업자 프로세스 관리의 최상위 수준에서만 가능하며 데이터베이스 요청을 직접 처리하지는 않습니다. DB 쿼리를 비동기 방식으로 처리하는 것이 실제로 좋은 전형적인 웹 응용 프로그램의 실제 예를 실제로보고 싶습니다.
JustAMartin
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.