ASP.NET MVC에서 비동기 작업을 수행하려면 .NET 4의 ThreadPool에서 스레드를 사용하십시오.


158

이 질문 후에 ASP.NET MVC에서 비동기 작업을 사용할 때 편안합니다. 그래서 나는 그것에 대해 두 개의 블로그 게시물을 썼습니다.

ASP.NET MVC의 비동기 작업에 대한 오해가 너무 많습니다.

항상이 문장을 듣습니다. 작업이 비동기 적으로 실행되면 응용 프로그램의 확장 성이 향상 될 수 있습니다

그리고 이런 종류의 문장도 많이 들었습니다. 대량의 트래픽이있는 경우 쿼리를 비동기 적으로 수행하지 않는 것이 좋습니다. 하나의 요청을 처리하기 위해 2 개의 추가 스레드를 소비하면 다른 들어오는 요청에서 리소스가 제거됩니다.

나는이 두 문장이 일치하지 않는다고 생각합니다.

스레드 풀이 ASP.NET에서 작동하는 방법에 대한 많은 정보는 없지만 스레드 풀의 크기가 스레드에 대해 제한된다는 것을 알고 있습니다. 따라서 두 번째 문장은이 문제와 관련이 있습니다.

그리고 ASP.NET MVC의 비동기 작업이 .NET 4의 ThreadPool에서 스레드를 사용하는지 알고 싶습니다.

예를 들어 AsyncController를 구현할 때 앱은 어떻게 구성됩니까? 트래픽이 많은 경우 AsyncController를 구현하는 것이 좋습니다.

ASP.NET MVC 3 (NET 4)의 비 동시성에 대한 거래를 설명 할 수있는 사람이 있습니까?

편집하다:

나는이 문서를 거의 수백 번 읽었으며 주요 거래를 이해하지만 여전히 일관성이없는 의견이 많기 때문에 혼란 스럽습니다.

ASP.NET MVC에서 비동기 컨트롤러 사용

편집하다:

아래와 같은 컨트롤러 동작이 있다고 가정 해 봅시다 ( AsyncController그러나 구현은 아님).

public ViewResult Index() { 

    Task.Factory.StartNew(() => { 
        //Do an advanced looging here which takes a while
    });

    return View();
}

당신이 여기에서 볼 수 있듯이, 나는 작업을 시작하고 잊어 버렸습니다. 그런 다음 완료되기를 기다리지 않고 즉시 돌아옵니다.

이 경우 스레드 풀의 스레드를 사용해야합니까? 그렇다면 완료 후 해당 스레드는 어떻게됩니까? 합니까이 GC오고가 완료 직후 청소?

편집하다:

@Darin의 답변을 위해 데이터베이스와 통신하는 비동기 코드 샘플이 있습니다.

public class FooController : AsyncController {

    //EF 4.2 DbContext instance
    MyContext _context = new MyContext();

    public void IndexAsync() { 

        AsyncManager.OutstandingOperations.Increment(3);

        Task<IEnumerable<Foo>>.Factory.StartNew(() => { 

           return 
                _context.Foos;
        }).ContinueWith(t => {

            AsyncManager.Parameters["foos"] = t.Result;
            AsyncManager.OutstandingOperations.Decrement();
        });

        Task<IEnumerable<Bars>>.Factory.StartNew(() => { 

           return 
                _context.Bars;
        }).ContinueWith(t => {

            AsyncManager.Parameters["bars"] = t.Result;
            AsyncManager.OutstandingOperations.Decrement();
        });

        Task<IEnumerable<FooBar>>.Factory.StartNew(() => { 

           return 
                _context.FooBars;
        }).ContinueWith(t => {

            AsyncManager.Parameters["foobars"] = t.Result;
            AsyncManager.OutstandingOperations.Decrement();
        });
    }

    public ViewResult IndexCompleted(
        IEnumerable<Foo> foos, 
        IEnumerable<Bar> bars,
        IEnumerable<FooBar> foobars) {

        //Do the regular stuff and return

    }
}

답은 확실하지 않지만 비동기 및 멀티 스레딩에 주목할 가치는 다릅니다. 따라서 비동기 처리로 고정 된 수의 스레드를 가질 수 있습니다. 어떤 페이지가 I / O를 위해 차단해야하는 경우 다른 페이지가 동일한 스레드에서 실행될 수 있습니다. 이 두 문장이 모두 참일 수있는 방법은 비동기가 일을 더 빠르게 만들 수 있지만 너무 많은 스레드가 문제입니다.
Chris Chilvers

@ChrisChilvers 그래, 비동기 작업에는 멀티 스레딩이 항상 필요한 것은 아니다. 나는 이미 그것을 알았지 만 내가 말할 수있는 한 컨트롤러가 없다고 생각합니다. AsyncController는 내 관점에서 원하는 수의 스레드를 스핀 업하지만 확실하지 않습니다. WPF와 같은 데스크톱 응용 프로그램에도 스레드 풀이라는 개념이 있습니까? 그런 종류의 앱에서는 스레드 수가 문제가되지 않는다고 생각합니다.
tugberk


두 번째 문은 많은 스레드를 의미 할 때 비동기식을 사용한다는 문제 (따라서 불일치)가 문제라고 생각합니다. 이는 asp.net이 비동기 페이지를 구현 한 방식이므로 특정 구현으로 인해 문제가 혼란 스럽기 때문일 수 있습니다 (문제를 일으키는 기능의 이름이 비동기 페이지이기 때문에). . 따라서 "다수 스레드"또는 "asp.net 버전 X 내의 비동기 페이지"를 의미합니다. 이후 버전에서는 구현이 변경 될 수 있습니다. 또는 스레드 풀을 사용하여 페이지 내에서 비동기를 수행하는 것을 의미합니다.
Chris Chilvers

@ChrisChilvers 아! 나는이 의견 후에 더 혼란스러워한다 : s
tugberk

답변:


177

여기의 우수한 기사 당신이 더 나은 (비동기 컨트롤러는 기본적으로 무엇을 나타내는 지입니다) ASP.NET에서 비동기 처리를 이해하는 읽기 추천 할 것입니다.

먼저 표준 동기 동작을 고려해 보겠습니다.

public ActionResult Index()
{
    // some processing
    return View();
}

이 조치를 요청하면 스레드 풀에서 스레드가 작성되고이 스레드에서이 조치의 본문이 실행됩니다. 따라서이 조치 내부의 처리가 느리면 전체 처리에 대해이 스레드를 차단하므로이 스레드를 재사용하여 다른 요청을 처리 할 수 ​​없습니다. 요청 실행이 끝나면 스레드가 스레드 풀로 리턴됩니다.

이제 비동기 패턴의 예를 보자.

public void IndexAsync()
{
    // perform some processing
}

public ActionResult IndexCompleted(object result)
{
    return View();
}

요청이 인덱스 조치로 전송되면 스레드 풀에서 스레드가 작성되고 IndexAsync메소드 본문 이 실행됩니다. 이 메소드의 본문이 실행을 마치면 스레드가 스레드 풀로 리턴됩니다. 그런 다음 표준을 사용하여 AsyncManager.OutstandingOperations비동기 작업의 완료를 알리면 스레드 풀에서 다른 스레드를 가져 IndexCompleted와서 작업 본문 이 실행되고 결과가 클라이언트에 렌더링됩니다.

따라서이 패턴에서 볼 수있는 것은 단일 클라이언트 HTTP 요청이 두 개의 다른 스레드에서 실행될 수 있다는 것입니다.

이제 흥미로운 부분이 IndexAsync메서드 내부에서 발생합니다 . 그 안에 차단 작업이있는 경우 작업자 스레드를 차단하기 때문에 비동기 컨트롤러의 전체 목적을 완전히 낭비하는 것입니다 (이 작업의 본문은 스레드 풀에서 가져온 스레드에서 실행됨을 기억하십시오).

그렇다면 언제 비동기 컨트롤러를 활용할 수 있습니까?

IMHO는 I / O 집약적 인 작업 (예 : 데이터베이스 및 원격 서비스에 대한 네트워크 호출)이있을 때 가장 많이 얻을 수 있습니다. CPU 집약적 인 작업이있는 경우 비동기 작업으로 많은 이점을 얻지 못합니다.

그렇다면 왜 I / O 집약적 운영의 이점을 얻을 수 있습니까? I / O 완료 포트를 사용할 수 있기 때문 입니다. IOCP는 전체 작업을 실행하는 동안 서버에서 스레드 또는 리소스를 사용하지 않기 때문에 매우 강력합니다.

그들은 어떻게 작동합니까?

WebClient.DownloadStringAsync 메소드를 사용하여 원격 웹 페이지의 컨텐츠를 다운로드한다고 가정하십시오 . 운영 체제 내에서 IOCP를 등록하고 즉시 돌아 오는이 메소드를 호출합니다. 전체 요청을 처리하는 동안 서버에서 스레드가 소비되지 않습니다. 모든 것은 원격 서버에서 발생합니다. 이 작업에는 많은 시간이 걸릴 수 있지만 작업자 스레드를 위험에 빠뜨리지 않으므로 신경 쓰지 않아도됩니다. 응답이 수신되면 IOCP에 신호가 전달되고 스레드 풀에서 스레드가 생성되고이 스레드에서 콜백이 실행됩니다. 그러나 보시다시피, 전체 프로세스 중에 스레드를 독점하지 않았습니다.

FileStream.BeginRead, SqlCommand.BeginExecute, ...와 같은 메소드에서도 마찬가지입니다.

여러 데이터베이스 호출을 병렬화하는 것은 어떻습니까? 4 개의 블로킹 데이터베이스 호출을 순서대로 수행하는 동기 제어기 조치가 있다고 가정하십시오. 각 데이터베이스 호출에 200ms가 걸리면 컨트롤러 작업을 실행하는 데 약 800ms가 걸린다는 것을 쉽게 계산할 수 있습니다.

이러한 호출을 순차적으로 실행할 필요가 없다면 병렬화하면 성능이 향상됩니까?

큰 질문인데 대답하기 쉽지 않습니다. 아마 그렇습니다, 아마 그렇습니다. 데이터베이스 호출을 구현하는 방법에 전적으로 의존합니다. 앞에서 설명한대로 비동기 컨트롤러 및 I / O 완료 포트를 사용하면 작업자 스레드를 독점하지 않기 때문에이 컨트롤러 작업 및 다른 작업의 성능을 향상시킵니다.

반면에 스레드 풀의 스레드에서 차단 데이터베이스 호출을 수행하여 제대로 구현하지 않으면 기본적 으로이 작업의 총 실행 시간을 약 200ms로 줄이지 만 작업자 스레드 4 개를 소비했을 것입니다. 풀에서 스레드를 처리하여 처리 할 수 ​​없어서 다른 요청의 성능이 저하되었을 수 있습니다.

따라서 매우 어렵고 응용 프로그램에서 광범위한 테스트를 수행 할 준비가되지 않았다면 비동기 컨트롤러를 구현하지 마십시오. 이점보다 더 많은 피해를 입을 수 있습니다. 예를 들어 표준 동기 컨트롤러 작업이 광범위한로드 테스트 및 측정을 수행 한 후 응용 프로그램에 병목 현상이 있음을 확인했습니다.

이제 당신의 예를 생각해 봅시다 :

public ViewResult Index() { 

    Task.Factory.StartNew(() => { 
        //Do an advanced looging here which takes a while
    });

    return View();
}

인덱스 조치에 대한 요청이 수신되면 스레드가 스레드 풀에서 스레드를 가져 와서 본문을 실행하지만 본문은 TPL을 사용하여 새 태스크 만 스케줄합니다 . 따라서 조치 실행이 종료되고 스레드가 스레드 풀로 리턴됩니다. 이를 제외하고 TPL 은 스레드 풀의 스레드를 사용하여 처리를 수행합니다. 따라서 원래 스레드가 스레드 풀로 리턴 된 경우에도이 풀에서 다른 스레드를 작성하여 태스크 본문을 실행했습니다. 그래서 당신은 당신의 소중한 수영장에서 2 실을 위태롭게했습니다.

이제 다음을 고려하십시오.

public ViewResult Index() { 

    new Thread(() => { 
        //Do an advanced looging here which takes a while
    }).Start();

    return View();
}

이 경우 스레드를 수동으로 생성합니다. 이 경우 인덱스 작업 본문 실행에 약간의 시간이 소요될 수 있습니다 (기존 풀에서 스레드를 생성하는 것보다 새 스레드를 생성하는 것이 더 비싸기 때문에). 그러나 고급 로깅 ​​작업의 실행은 풀의 일부가 아닌 스레드에서 수행됩니다. 따라서 우리는 다른 요청을 처리하기 위해 무료로 남아있는 풀의 스레드를 위태롭게하지 않습니다.


1
정말 자세한 감사합니다! 메서드 System.Threading.Task안에서 4 개의 비동기 작업 ( )이 실행되고 있다고 가정 해 봅시다 IndexAsync. 이러한 작업 내에서 서버를 db 호출하고 있습니다. 따라서 모두 I / O 집약적 인 작업입니까? 이 경우 4 개의 개별 스레드를 작성합니까 (또는 스레드 풀에서 4 개의 개별 스레드를 가져옴)? 멀티 코어 머신이 병렬로 실행될 것이라고 가정합니까?
tugberk

10
@tugberk, 데이터베이스 호출은 I / O 작업이지만 구현 방법에 따라 다릅니다. SqlCommand.ExecuteReader차단 호출이므로 모든 것을 낭비하는 것과 같은 차단 데이터베이스 호출을 사용하는 경우 . 이 호출이 실행되는 스레드를 차단하고 있으며이 스레드가 풀의 스레드 인 경우 매우 나쁩니다. I / O 완료 포트를 사용하는 경우에만 혜택이 있습니다 : SqlCommand.BeginExecuteReader. 어떤 작업을하든 IOCP를 사용하지 않으면 응용 프로그램의 전체 성능에 대한 이점보다 더 많은 손상을 입히기 때문에 비동기 컨트롤러를 사용하지 마십시오.
Darin Dimitrov

1
대부분의 경우 EF 코드를 먼저 사용합니다. 그것이 맞는지 잘 모르겠습니다. 나는 내가 일반적으로하는 일을 보여주는 샘플을 작성했습니다. 질문을 업데이트했는데 살펴볼 수 있습니까?
tugberk

3
@ tugberk, 당신은 그것들을 병렬로 실행하고 있기 때문에 총 실행 시간은 순차적으로 실행하는 것과 비교하여 적습니다. 그러나 그들을 실행하기 위해 작업자 스레드를 사용합니다. 실제로 EF는 게 으르므로 실제로 할 때는 _context.Foo아무것도 실행하지 않습니다. 당신은 표현 트리를 구축하고 있습니다. 이것을 조심하십시오. 결과 집합을 열거하기 시작할 때만 쿼리 실행이 지연됩니다. 그리고 이것이보기에서 발생하면 성능에 치명적일 수 있습니다. .ToList()끝에 EF 쿼리 추가를 열심히 실행합니다 .
Darin Dimitrov

2
@tugberk, 웹 사이트에서 여러 사용자를 병렬로 시뮬레이션하여로드가 많은 상황에서 어떻게 작동하는지 확인하려면로드 테스트 도구가 필요합니다. 미니 프로파일 러는 웹 사이트의로드를 시뮬레이션 할 수 없습니다. ADO.NET 쿼리를보고 최적화하고 단일 요청을 프로파일 링하는 데 도움이 될 수 있으며, 많은 사용자가 사이트를 방문 할 때 실제 상황에서 사이트가 어떻게 작동하는지 확인해야 할 때 쓸모가 없습니다.
Darin Dimitrov

49

예-모든 스레드가 스레드 풀에서 나옵니다. 요청이 새 스레드에 들어올 때 MVC 앱은 이미 다중 스레드입니다. 풀에서 가져 와서 요청을 처리하는 데 사용됩니다. 요청이 완전히 서비스되고 완료 될 때까지 해당 스레드는 (다른 요청에서) '잠금'됩니다. 풀에 사용 가능한 스레드가없는 경우 요청은 사용 가능한 스레드가 될 때까지 기다려야합니다.

비동기 컨트롤러가있는 경우 여전히 풀에서 스레드를 얻지 만 요청을 처리하는 동안 스레드가 포기되고 무언가가 발생할 때까지 (및 해당 스레드가 다른 요청에 제공 될 수 있음) 원래 요청에 스레드가 필요한 경우 다시 수영장에서 하나를 가져옵니다.

차이점은 스레드가 무언가로부터 응답을 기다리는 많은 장기 실행 요청이있는 경우 풀에서 스레드가 부족하여 기본 요청까지 처리 할 수 ​​있다는 것입니다. 비동기 컨트롤러가있는 경우 더 이상 스레드가 없지만 대기중인 스레드는 풀로 반환되어 다른 요청을 처리 할 수 ​​있습니다.

거의 실생활의 예 ... 버스에 점점처럼 생각, 거기는 처음에 도착 지불에 도착을 기다리고 오명이고 (운전자가 자신의 요청을 서비스), 당신이 얻을 앉는다 (드라이버가 서비스하는 귀하의 요청)하지만 돈을 찾을 수 없습니다. 당신이 당신의 주머니에서 비틀 거리면서 운전자가 당신을 포기하고 다음 두 사람을 (요청에 응함) 얻습니다. 당신은 끝났지 만 당신이 봉사하는 절반의 길에있는 동안 세 번째와 네 번째 사람들이 봉사되었습니다. 이것은 드라이버가 수영장에서 유일하고 스레드이며 승객이 요청임을 의미합니다. 두 명의 드라이버가 있으면 어떻게 작동하는지 작성하기가 너무 복잡했지만 상상할 수 있습니다 ...

비동기 컨트롤러가 없다면, 버스 운전사가 일을하지 않는 동안 뒤에 승객들은 돈을 찾는 동안 나이를 기다려야 할 것입니다.

결론적으로 많은 사람들이 돈이 어디에 있는지 알지 못한다면 (즉, 운전자가 요청한 것에 응답하는 데 오랜 시간이 걸리는 경우) 비동기 컨트롤러는 요청의 처리량을 도와서 일부 프로세스의 속도를 높일 수 있습니다. 인공 지능 컨트롤러가 없으면 모든 사람이 앞 사람이 완전히 다룰 때까지 기다립니다. 그러나 MVC에서는 단일 버스에 많은 버스 드라이버가 있으므로 비동기가 자동 선택이 아니라는 것을 잊지 마십시오.


8
아주 좋은 비유입니다. 감사합니다.
피츠버그 DBA

나는 설명을 좋아했다. 감사합니다
Omer Cansizoglu

감사합니다
Anand Vyas

Darin의 답변과 함께 귀하의 답변은 비동기 컨트롤러의 모든 메커니즘, 그것이 무엇인지, 그리고 더 중요하지 않은 것을 요약합니다!
Nirman

이것은 좋은 비유이지만 내 유일한 질문은 이것입니다. 비유에서 주머니에 얽힌 사람은 응용 프로그램에서 일종의 작업 / 처리가 될 것입니다 ... 그래서 스레드를 해제하면 어떤 프로세스가 작동합니까? 분명히 다른 스레드입니까? 그래서 우리는 여기서 무엇을 얻습니까?
Tomuke

10

여기에는 두 가지 개념이 있습니다. 우선 코드를 병렬로 실행하여 사용자가 기다리지 않도록 다른 스레드에서 코드를 더 빠르게 실행하거나 예약 할 수 있습니다. 당신이 가진 예

public ViewResult Index() { 

    Task.Factory.StartNew(() => { 
        //Do an advanced looging here which takes a while
    });

    return View();
}

두 번째 카테고리에 속합니다. 사용자는 더 빠른 응답을 얻을 수 있지만 동일한 작업을 수행하고 스레딩을 처리해야하기 때문에 서버의 총 워크로드가 더 높습니다.

이것의 또 다른 예는 다음과 같습니다.

public ViewResult Index() { 

    Task.Factory.StartNew(() => { 
        //Make async web request to twitter with WebClient.DownloadString()
    });

    Task.Factory.StartNew(() => { 
        //Make async web request to facebook with WebClient.DownloadString()
    });


    //wait for both to be ready and merge the results

    return View();
}

요청이 병렬로 실행되기 때문에 사용자는 직렬로 수행되는 것처럼 기다릴 필요가 없습니다. 그러나 스레드 대기 상태에있는 동안 많은 스레드에서 코드를 실행하기 때문에 직렬로 실행하는 경우보다 여기에서 더 많은 리소스를 사용한다는 것을 알고 있어야합니다.

이것은 클라이언트 시나리오에서 완벽하게 좋습니다. 그리고 새로운 작업에서 동기식 장기 실행 코드를 래핑 (다른 스레드에서 실행)하는 것도 UI를 신속하게 처리하거나 병렬화하여 유지하는 것이 일반적입니다. 스레드는 여전히 전체 기간 동안 사용됩니다. 로드가 많은 서버에서는 실제로 더 많은 리소스를 사용하기 때문에 역효과가 발생할 수 있습니다. 사람들이 경고 한 내용입니다.

MVC의 비동기 컨트롤러는 또 다른 목표가 있습니다. 여기서 요점은 스레드가 아무것도하지 않는 주위에 앉지 않도록하는 것입니다 (확장 성을 해칠 수 있음). 호출하는 API에 비동기 메소드가 있는지 여부 만 중요합니다. WebClient.DowloadStringAsync ()와 같습니다.

요점은 웹 요청이 완료 될 때까지 스레드가 반환되어 새 요청을 처리하도록 할 수 있다는 것입니다. 웹 요청은 동일한 또는 새 스레드를 가져 와서 요청을 완료하는 콜백을 호출합니다.

비동기와 병렬의 차이점을 이해하기를 바랍니다. 병렬 코드는 스레드가 둘러 앉아 결과를 기다리는 코드로 생각하십시오. 비동기 코드는 코드가 완료되면 알림을 받고 다시 작업 할 수있는 코드이지만 스레드는 다른 작업을 수행 할 수 있습니다.


6

작업이 비동기 적으로 실행 되는 경우 추가 작업을 처리하는 데 사용할 수있는 리소스가있는 경우에만 응용 프로그램 확장 할 수 있습니다 .

비동기 작업은 기존 작업이 진행 중이므로 작업을 차단하지 않습니다. ASP.NET에는 여러 요청을 나란히 실행할 수있는 비동기 모델이 있습니다. 요청을 대기열에 넣고 FIFO를 처리하는 것이 가능하지만, 수백 개의 요청이 대기열에 있고 각 요청이 처리하는 데 100ms가 걸리면 확장 성이 떨어집니다.

많은 양의 트래픽 있는 경우 요청을 처리 할 추가 리소스가 없을 수 있으므로 쿼리를 비동기 적으로 수행하지 않는 것이 좋습니다 . 여분의 리소스가 없으면 요청이 대기열에 들어가거나 기하 급수적으로 더 길거나 완전히 실패합니다.이 경우 비동기 오버 헤드 (뮤텍스 및 컨텍스트 전환 작업)가 아무 것도 제공하지 않습니다.

ASP.NET은 선택의 여지가 없습니다. 비동기 모델을 사용합니다. 이것이 서버-클라이언트 모델에 적합하기 때문입니다. 모든 요청간에 공유되는 리소스를 관리하려고하지 않는 한 비동기 패턴을 사용하여 더 나은 확장을 시도하는 내부 코드를 내부적으로 작성해야하는 경우에는 이미 래핑되어 있기 때문에 실제로 개선 된 부분은 보이지 않습니다. 다른 것을 차단하지 않는 비동기 프로세스에서.

궁극적으로 시스템에서 병목 현상을 일으키는 원인을 실제로 확인할 때까지는 모두 주관적입니다. 때로는 대기중인 리소스 차단을 방지하여 비동기 패턴이 도움이되는 위치가 분명합니다. 궁극적으로 시스템 측정 및 분석 만이 효율성을 얻을 수있는 곳을 나타낼 수 있습니다.

편집하다:

귀하의 예에서 Task.Factory.StartNew호출은 .NET 스레드 풀에서 작업을 대기시킵니다. 스레드 풀 스레드의 특성은 많은 스레드를 작성 / 파기하는 비용을 피하기 위해 재사용해야합니다. 작업이 완료되면 스레드가 풀로 다시 풀려 다른 요청에 의해 재사용됩니다 (가비지 수집기는 작업에서 일부 개체를 만들지 않은 한 실제로 참여하지 않습니다.이 경우 정상적인 경우에 따라 수집 됨) 범위 지정).

ASP.NET에 관한 한 여기에는 특별한 작업이 없습니다. ASP.NET 요청은 비동기 작업과 관계없이 완료됩니다. 스레드 풀이 포화 상태 인 경우 (즉, 요청을 처리하는 데 사용할 수있는 스레드가없고 풀 설정에서 더 많은 스레드를 작성할 수없는 경우) 유일한 문제는 요청이 시작 대기 중으로 차단되는 경우입니다 풀 스레드를 사용할 수있을 때까지 작업 .


감사! 답변을 읽은 후 코드 샘플로 질문을 편집했습니다. 당신은 볼 수 있습니까?
tugberk

당신은 저에게 마술 문장을 가지고 있습니다 : Task.Factory.StartNewcall은 .NET 스레드 풀에서 작업을 대기열에 넣습니다. . 이 문맥에서 어느 것이 여기에 맞는가 : 1-) 새 스레드를 작성하고 완료되면 해당 스레드는 스레드 풀로 돌아가서 다시 재사용되기를 기다립니다. 2-) 스레드 풀에서 스레드를 가져오고 해당 스레드는 스레드 풀로 돌아가서 다시 재사용되기를 기다립니다. 3-) 가장 효율적인 접근 방식을 취하며 둘 중 하나를 수행 할 수 있습니다.
tugberk

1
스레드 풀은 필요에 따라 스레드를 작성하고 사용하지 않을 때 스레드를 재순환합니다. 정확한 동작은 CLR 버전마다 다릅니다. 자세한 내용은 여기를 참조
Paul Turner

지금 내 마음에 형성되기 시작합니다. CLR은 스레드 풀을 소유하고 있습니다. 예를 들어 WPF 응용 프로그램에는 스레드 풀이라는 개념이 있으며 해당 풀도 처리합니다.
tugberk

1
스레드 풀은 CLR 내에서 고유 한 것입니다. 풀을 "인식"하는 다른 구성 요소는 자체 구성 요소를 만들고 파괴하는 대신 스레드 풀 스레드 (적절한 경우)를 사용하고 있음을 나타냅니다. 스레드를 작성하거나 삭제하는 것은 상대적으로 비용이 많이 드는 작업이므로 풀을 사용하면 단기 실행 작업에서 효율성이 크게 향상됩니다.
Paul Turner

2

예, 스레드 풀의 스레드를 사용합니다. 실제로 모든 질문 등을 다루는 MSDN의 훌륭한 가이드가 있습니다. 나는 그것이 과거에 꽤 유용하다는 것을 알았습니다. 확인 해봐!

http://msdn.microsoft.com/en-us/library/ee728598.aspx

한편 비동기 코드에 대해 듣는 의견 + 제안은 소금 한 덩어리로 가져와야합니다. 우선, 무언가를 비동기식으로 만드는 것이 반드시 확장 성을 향상시키는 것은 아니며 경우에 따라 응용 프로그램의 확장 성을 악화시킬 수 있습니다. "대량의 트래픽 ..."에 대해 게시 한 다른 의견도 특정 상황에서만 정확합니다. 실제로는 작업이 수행하는 작업과 시스템의 다른 부분과 어떻게 상호 작용하는지에 달려 있습니다.

요컨대, 많은 사람들이 비동기에 대해 많은 의견을 가지고 있지만 상황에 맞지 않을 수도 있습니다. 정확한 문제에 중점을두고 기본 성능 테스트를 수행하여 비동기 컨트롤러 등이 실제로 응용 프로그램에서 처리하는 것을 확인 합니다 .


나는 그 문서를 수백 번 읽었지만 여전히 많은 혼란을 겪고 있습니다 (아마도 문제는 나일 것입니다). 주위를 둘러 보면 ASP.NET MVC의 비동기에 대한 의견이 너무 많아서 내 질문에서 볼 수 있습니다.
tugberk

마지막 문장 : 컨트롤러 작업 내에서 데이터베이스를 별도로 5 번 쿼리하고 (필수) 약 400ms가 걸렸습니다. 그런 다음 AsyncController를 구현하고 병렬로 실행했습니다. 응답 시간이 대폭 단축되었습니다. 200ms 그러나 얼마나 많은 스레드가 생성되는지, 스레드가 완료 된 후 그 스레드에 어떤 일이 발생하는지, 그리고 완료 된 직후에 스레드를 GC정리하고 정리하여 앱에 메모리 누수가 발생하지 않도록합니다. 그 부분에 대한 아이디어.
tugberk

디버거를 연결하고 찾으십시오.
AR

0

우선 MVC가 아니라 스레드 풀을 유지 관리하는 IIS입니다. 따라서 MVC 또는 ASP.NET 응용 프로그램에 대한 모든 요청은 스레드 풀에서 유지 관리되는 스레드에서 제공됩니다. Asynch 앱을 만들 때만 다른 스레드에서이 작업을 호출하고 스레드를 즉시 해제하여 다른 요청을 처리 할 수 ​​있습니다.

MVC에서 스레드 기아가 발생하는 방식과 MVC를 사용하여 최소화하는 방법을 보여주는 세부 비디오 ( http://www.youtube.com/watch?v=wvg13n5V0V0/ "MVC 비동기 컨트롤러 및 스레드 기아")와 동일하게 설명했습니다. Asynch controllers. 또한 perfmon을 사용하여 요청 큐를 측정하여 MVC 비동기의 요청 큐가 감소하는 방법과 Synch 작업의 최악의 상태를 확인할 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.