Programing

동기 코드를 비동기 호출로 래핑

crosscheck 2020. 10. 15. 07:31
반응형

동기 코드를 비동기 호출로 래핑


ASP.NET 응용 프로그램에 완료하는 데 많은 시간이 소요되는 메서드가 있습니다. 이 메소드에 대한 호출은 사용자가 제공하는 캐시 상태 및 매개 변수에 따라 한 사용자 요청 중에 최대 3 번 발생할 수 있습니다. 각 호출을 완료하는 데 약 1-2 초가 걸립니다. 메서드 자체는 서비스에 대한 동기 호출이며 구현을 재정의 할 가능성이 없습니다.
따라서 서비스에 대한 동기 호출은 다음과 같습니다.

public OutputModel Calculate(InputModel input)
{
    // do some stuff
    return Service.LongRunningCall(input);
}

그리고 메소드의 사용법은 다음과 같습니다 (메소드 호출이 두 번 이상 발생할 수 있음).

private void MakeRequest()
{
    // a lot of other stuff: preparing requests, sending/processing other requests, etc.
    var myOutput = Calculate(myInput);
    // stuff again
}

이 방법의 동시 작업을 제공하기 위해 내 측면에서 구현을 변경하려고 시도했으며 여기에 지금까지 온 것이 있습니다.

public async Task<OutputModel> CalculateAsync(InputModel input)
{
    return await Task.Run(() =>
    {
        return Calculate(input);
    });
}

사용법 ( "다른 작업 수행"코드의 일부는 서비스 호출과 동시에 실행 됨) :

private async Task MakeRequest()
{
    // do some stuff
    var task = CalculateAsync(myInput);
    // do other stuff
    var myOutput = await task;
    // some more stuff
}

내 질문은 다음과 같습니다. ASP.NET 응용 프로그램에서 실행 속도를 높이기 위해 올바른 접근 방식을 사용합니까? 아니면 동기 코드를 비동기 적으로 실행하려는 불필요한 작업을 수행하고 있습니까? 두 번째 접근 방식이 ASP.NET에서 옵션이 아닌 이유를 설명 할 수있는 사람이 있습니까 (정말 그렇지 않은 경우)? 또한 그러한 접근 방식이 적용 가능하다면, 현재 우리가 수행 할 수있는 유일한 호출 인 경우 이러한 메서드를 비동기식으로 호출해야합니까 (완료를 기다리는 동안 수행 할 다른 작업이없는 경우)?
이 주제에 대한 인터넷의 대부분의 기사는 async-await이미 awaitable메소드를 제공하는 코드를 사용한 접근 방식을 다루지 만 제 경우는 아닙니다. 여기병렬 호출의 상황을 설명하지 않고 동기화 호출을 래핑하는 옵션을 거부하는 내 사례를 설명하는 멋진 기사이지만 내 생각에는 내 상황이 바로 그 기회입니다.
도움과 팁에 미리 감사드립니다.


서로 다른 두 가지 유형의 동시성을 구별하는 것이 중요합니다. 비동기 동시성은 비행 중에 여러 비동기 작업이있는 경우입니다 (각 작업이 비동기이므로 실제로 스레드를 사용하지 않는 작업이 있음 ). 병렬 동시성은 각각 별도의 작업을 수행하는 여러 스레드가있는 경우입니다.

가장 먼저 할 일은이 가정을 재평가하는 것입니다.

메서드 자체는 서비스에 대한 동기식 호출이며 구현을 재정의 할 가능성이 없습니다.

"서비스"가 서비스 또는 I / O 바운드 인 경우 가장 좋은 솔루션은 이에 대한 비동기 API를 작성하는 것입니다.

"서비스"가 웹 서버와 동일한 시스템에서 실행되어야하는 CPU 바운드 작업이라는 가정을 진행하겠습니다.

그렇다면 다음으로 평가할 것은 또 다른 가정입니다.

더 빨리 실행하려면 요청이 필요합니다.

그게 당신이해야 할 일이라고 절대적으로 확신합니까? 대신 수행 할 수있는 프런트 엔드 변경이 있습니까? 예를 들어 요청을 시작하고 처리하는 동안 사용자가 다른 작업을 수행하도록 허용합니까?

예, 개별 요청을 더 빠르게 실행해야한다는 가정을 계속하겠습니다.

In this case, you'll need to execute parallel code on your web server. This is most definitely not recommended in general because the parallel code will be using threads that ASP.NET may need to handle other requests, and by removing/adding threads it will throw the ASP.NET threadpool heuristics off. So, this decision does have an impact on your entire server.

When you use parallel code on ASP.NET, you are making the decision to really limit the scalability of your web app. You also may see a fair amount of thread churn, especially if your requests are bursty at all. I recommend only using parallel code on ASP.NET if you know that the number of simultaneous users will be quite low (i.e., not a public server).

So, if you get this far, and you're sure you want to do parallel processing on ASP.NET, then you have a couple of options.

One of the easier methods is to use Task.Run, very similar to your existing code. However, I do not recommend implementing a CalculateAsync method since that implies the processing is asynchronous (which it is not). Instead, use Task.Run at the point of the call:

private async Task MakeRequest()
{
  // do some stuff
  var task = Task.Run(() => Calculate(myInput));
  // do other stuff
  var myOutput = await task;
  // some more stuff
}

Alternatively, if it works well with your code, you can use the Parallel type, i.e., Parallel.For, Parallel.ForEach, or Parallel.Invoke. The advantage to the Parallel code is that the request thread is used as one of the parallel threads, and then resumes executing in the thread context (there's less context switching than the async example):

private void MakeRequest()
{
  Parallel.Invoke(() => Calculate(myInput1),
      () => Calculate(myInput2),
      () => Calculate(myInput3));
}

I do not recommend using Parallel LINQ (PLINQ) on ASP.NET at all.

참고URL : https://stackoverflow.com/questions/21406973/wrapping-synchronous-code-into-asynchronous-call

반응형