itsource

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

mycopycode 2023. 5. 2. 22:40
반응형

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

나는 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 하 접 코 로 다 드 는 니 ▁with ,awaitable방법, 하지만 그건 내 경우가 아닙니다.여기 병렬 통화의 상황을 설명하지 않는 제 사례를 설명하는 멋진 기사가 있습니다. 동기 통화를 마무리하는 옵션을 거부하는 것입니다. 하지만 제 생각에는 제 상황이 바로 그것을 할 수 있는 기회입니다.

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

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

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

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

저는 당신의 "서비스"가 웹 서버와 동일한 컴퓨터에서 실행되어야 하는 CPU 바인딩 작업이라는 가정으로 진행하겠습니다.

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

더 빨리 실행하기 위해 요청이 필요합니다.

그게 당신이 해야 할 일이라고 확신하십니까?요청을 시작하고 처리하는 동안 사용자가 다른 작업을 수행할 수 있도록 허용하는 등 프런트 엔드에서 변경할 수 있는 사항이 있습니까?

예, 개별 요청을 더 빨리 실행해야 한다는 가정 하에 진행하겠습니다.

이 경우 웹 서버에서 병렬 코드를 실행해야 합니다.병렬 코드는 ASP 스레드를 사용하기 때문에 일반적으로 권장되지 않습니다.NET은 다른 요청을 처리해야 할 수 있으며 스레드를 제거/추가하면 ASP를 던집니다.NET 스레드 풀 휴리스틱이 꺼집니다.따라서 이 결정은 전체 서버에 영향을 미칩니다.

ASP에서 병렬 코드를 사용하는 경우.NET, 당신은 당신의 웹 앱의 확장성을 정말로 제한하기로 결정했습니다.특히 요청이 폭주할 경우 상당한 양의 스레드 회전을 볼 수도 있습니다.ASP에서는 병렬 코드만 사용하는 것이 좋습니다.동시 사용자 수가 상당히 적을 경우(즉, 공용 서버가 아님) NET.

여기까지 와서 ASP에서 병렬 처리를 수행해야 합니다.NET에는 몇 가지 옵션이 있습니다.

중 는 가장쉬방중하를 사용하는 입니다.Task.Run기존 코드와 매우 유사합니다.그러나 다음을 구현하는 것은 권장하지 않습니다.CalculateAsync이는 처리가 비동기적이라는 것을 의미하기 때문입니다(그렇지는 않습니다).대신에, 신대사를 하세요.Task.Run통화 시점:

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

잘▁use▁altern다를 사용할 수 있습니다.Parallel 형유, 즉,Parallel.For,Parallel.ForEach또는Parallel.InvokeParallel스레드 중 된 후 입니다(" "" " " " " "전환이 ." " " " " " " " " 보다 컨텍스트 전환이 적습니다.async예):

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

ASP에서 병렬 LINQ(PLINQ)를 사용하지 않는 것이 좋습니다.NET 전혀.

다음 코드가 작업을 항상 비동기식으로 실행하도록 변환할 수 있음을 발견했습니다.

private static async Task<T> ForceAsync<T>(Func<Task<T>> func)
{
    await Task.Yield();
    return await func();
}

그리고 나는 그것을 다음과 같은 방법으로 사용했습니다.

await ForceAsync(() => AsyncTaskWithNoAwaits())

이렇게 하면 작업이 비동기적으로 실행되므로 작업을 WhenAll, WhenAny 시나리오 및 기타 용도로 결합할 수 있습니다.

태스크를 간단히 추가할 수도 있습니다.호출된 코드의 첫 번째 줄로 양보()를 지정합니다.

이것은 아마도 당신의 경우에서 가장 쉬운 일반적인 방법일 것입니다.

return await new Task(
    new Action(
        delegate () { 
          // put your synchronous code here
        }
    )
);

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

반응형