나는 뭔가를 이해하지 못한다고 생각합니다. 나는 그것을 생각했다.Task.Yield()
새로운 스레드 / 컨텍스트가 작업을 위해 시작되도록 강요하지만이 답을 다시 읽는다.그것은 단순히 메서드를 비동기로 만듭니다. 그것은 여전히 같은 맥락에있을 것입니다.
교착 상태가 발생하지 않고 여러 작업을 병렬로 생성하고 실행하는 올바른 방법은 asp.net 프로세스에서 무엇입니까?
즉, 다음과 같은 방법이 있다고 가정합니다.
async Task createFileFromLongRunningComputation(int input) {
//many levels of async code
}
그리고 특정 POST 경로에 도달하면 위의 방법을 동시에 3 번 실행하고 싶습니다.즉시 반환, 세 가지 모두 완료되면 기록하십시오.
나는 내 행동에 이런 것을 넣어야한다고 생각한다.
public IHttpAction Post() {
Task.WhenAll(
createFileFromLongRunningComputation(1),
createFileFromLongRunningComputation(2),
createFileFromLongRunningComputation(3)
).ContinueWith((Task t) =>
logger.Log("Computation completed")
).ConfigureAwait(false);
return Ok();
}
무엇이 들어가야하는지createFileFromLongRunningComputation
? 나는 생각했다.Task.Yield
맞았지 만 분명히 그렇지 않다.
그만큼옳은동시 작업을 다른 스레드로 오프로드하는 방법은Task.Run
로시 피디아가 제안한대로.
에서 백그라운드 처리를위한 최상의 솔루션ASP.Net(귀하의AppDomain
모든 작업과 함께 자동으로 재활용 / 종료 될 수 있음)스콧 한젤 만과스티븐 클리어 리님의 블로그 (예 : HangFire)
그러나, 당신은할 수 있었다이용하다Task.Yield
함께ConfigureAwait(false)
같은 것을 달성하기 위해.
모든Task.Yield
그렇지 않으면 메소드의 나머지 부분이 동 기적으로 진행되지 않도록 대기하는 것이 반환됩니다 (IsCompleted
반환false
과OnCompleted
~을 실행하다Action
매개 변수).ConfigureAwait(false)
무시하다SynchronizationContext
나머지 메서드는 강제로 실행되도록합니다.ThreadPool
실.
두 가지를 함께 사용하면async
메서드는 즉시 실행되는 작업을 반환합니다.ThreadPool
실Task.Run
) :
async Task CreateFileFromLongRunningComputation(int input)
{
await Task.Yield().ConfigureAwait(false);
// executed on a ThreadPool thread
}
편집하다:
George Mauer는 다음과 같이 지적했다.Task.Yield
보고YieldAwaitable
너는 사용할 수 없어.ConfigureAwait(false)
이 방법은Task
수업.
다음과 같이 비슷한 것을 얻을 수 있습니다.Task.Delay
매우 짧은 시간 제한으로 동기식이 아니지만 많은 시간을 낭비하지 않아도됩니다.
async Task CreateFileFromLongRunningComputation(int input)
{
await Task.Delay(1).ConfigureAwait(false);
// executed on a ThreadPool thread
}
더 나은 옵션은YieldAwaitable
단순히SynchronizationContext
사용하는 것과 같다.ConfigureAwait(false)
않습니다 :
async Task CreateFileFromLongRunningComputation(int input)
{
await new NoContextYieldAwaitable();
// executed on a ThreadPool thread
}
public struct NoContextYieldAwaitable
{
public NoContextYieldAwaiter GetAwaiter() { return new NoContextYieldAwaiter(); }
public struct NoContextYieldAwaiter : INotifyCompletion
{
public bool IsCompleted { get { return false; } }
public void OnCompleted(Action continuation)
{
var scheduler = TaskScheduler.Current;
if (scheduler == TaskScheduler.Default)
{
ThreadPool.QueueUserWorkItem(RunAction, continuation);
}
else
{
Task.Factory.StartNew(continuation, CancellationToken.None, TaskCreationOptions.PreferFairness, scheduler);
}
}
public void GetResult() { }
private static void RunAction(object state) { ((Action)state)(); }
}
}
이것은 권장 사항이 아니라 Task.Yield 질문에 대한 답변입니다.
Task.Yield()
작업을 반환하지 않으므로 아무 작업도 수행되지 않습니다.ConfigureAwait
기능. 그래서 권장되지 않는 접근 방식은 효과가 없습니다. - George Mauer
(라르 논의 대답올바른 것입니다. 이 답변은 OP가 제기 한 접근 방식이 좋은 것인지에 대한 논의가 더 많습니다.)
정말로 특별한 것은 필요 없습니다. 그만큼createFileFromLongRunningComputation
메서드는 특별한 것이 필요하지 않습니다.await
일부 비동기 메소드를 호출하고ConfigureAwait(false)
할까요교착 상태를 피하십시오. 평범한 것에서 아무것도하지 않는다고 가정하십시오 (아마도 메서드 이름이 주어지면 단지 파일 I / O 일 것입니다).
경고:
이것은 위험합니다. 작업이 너무 오래 끝내면 ASP.net은이 상황에서 당신 밑에서 깔개를 꺼낼 가능성이 큽니다.
의견 제시 자 중 한 명이 지적했듯이이를 달성하는 더 좋은 방법이 있습니다. 그들 중 하나는HostingEnvironment.QueueBackgroundWorkItem
(.NET 4.5.2 이상에서만 사용 가능).
장기 실행 계산이 완료하는 데 오랜 시간이 걸리는 경우 ASP.net에서 완전히 제외하는 것이 좋습니다. 이러한 상황에서 더 좋은 방법은 일종의 메시지 큐와 IIS / ASP.net 외부에서 이러한 메시지를 처리하는 서비스를 사용하는 것입니다.
Run
; 스레드 풀에서 작업을 예약하는 데 시간 낭비가 있습니다.스타트비동기 조작. - Servy
ConfigureAwait
네가 실제로 그렇게하지 않으면 무의미하다.await
그만큼Task
. - Servy