2013-08-30 2 views
12

Delay(0)은 항상 인라인됩니까? 내 경험상 다음과 같습니다.Task.Yield()와 Task.Delay (0)

using System; 
using System.Threading; 
using System.Threading.Tasks; 

namespace ConsoleApplication 
{ 
    class Program 
    { 
     static async Task Test() 
     { 
      await Task.Yield(); 
      Console.WriteLine("after Yield(), thread: {0}", Thread.CurrentThread.ManagedThreadId); 
      await Task.Delay(0); 
      Console.WriteLine("after Delay(0), thread: {0}", Thread.CurrentThread.ManagedThreadId); 
      await Task.Delay(100); 
      Console.WriteLine("after Delay(100), thread: {0}", Thread.CurrentThread.ManagedThreadId); 
     } 
     static void Main(string[] args) 
     { 
      Console.WriteLine("Main thread: {0}", Thread.CurrentThread.ManagedThreadId); 
      Test().Wait(); 
     } 
    } 
} 

이것은 콘솔 응용 프로그램이므로 스레드 풀은 계속 사용됩니다. 출력 : Task.Delay 내부

Main thread: 11 
after Yield(), thread: 7 
after Delay(0), thread: 7 
after Delay(100), thread: 6 

답변

21

, 그것은 다음과 같습니다가 (단일 매개 변수 (int) 버전 바로 아래 버전을 호출) :

[__DynamicallyInvokable] 
public static Task Delay(int millisecondsDelay, CancellationToken cancellationToken) 
{ 
    if (millisecondsDelay < -1) 
    { 
     throw new ArgumentOutOfRangeException("millisecondsDelay", Environment.GetResourceString("Task_Delay_InvalidMillisecondsDelay")); 
    } 
    if (cancellationToken.IsCancellationRequested) 
    { 
     return FromCancellation(cancellationToken); 
    } 
    if (millisecondsDelay == 0) 
    { 
     return CompletedTask; 
    } 
    DelayPromise state = new DelayPromise(cancellationToken); 
    if (cancellationToken.CanBeCanceled) 
    { 
     state.Registration = cancellationToken.InternalRegisterWithoutEC(delegate (object state) { 
      ((DelayPromise) state).Complete(); 
     }, state); 
    } 
    if (millisecondsDelay != -1) 
    { 
     state.Timer = new Timer(delegate (object state) { 
      ((DelayPromise) state).Complete(); 
     }, state, millisecondsDelay, -1); 
     state.Timer.KeepRootedWhileScheduled(); 
    } 
    return state; 
} 

당신은 희망이 볼 수 있듯이 :

if (millisecondsDelay == 0) 
    { 
     return CompletedTask; 
    } 

즉, 항상 완료된 작업을 반환하므로 코드는 항상 해당 await 행을지나 계속 실행됩니다.

8

예. 반사경의 일리노이 검사 (다른 논리 중에서) :

if (millisecondsDelay == 0) 
{ 
    return CompletedTask; 
} 

그래,이 경우 이미 완료된 작업을 되돌릴 것입니다.

await의 구현에는 이미 완료된 작업이 추가 컨텍스트 전환을 일으키지 않는지 확인하는 검사가 포함되어 있으므로 예 : 코드가 여기 숨을 멈추지 않고 계속 실행됩니다.

이미 완료된 작업을 반환하는 것은 대답이 이미 알려져 있거나 동 기적으로 사용 가능한 경우 권장되는 트릭입니다. 일반적인 결과 값에 대해서는 Task을 캐시하는 것이 일반적입니다.

+0

감사합니다. 나에게 비 완성형 [작업 완료 상태의 작업]을 만드는 편리한 방법처럼 보입니다 (http://stackoverflow.com/a/18527377/1768303). 기술적으로 그는 데미안의 대답을 받아 들였습니다.] – Noseratio

+0

@Noseratio 나는'Task completed = Task.FromResult (true); '와 같은 것을 사용하는 것이 더 효과적이라고 생각합니다. 나는'Task.Delay (0)'은 완료된'Task'를 반환 할 필요가 없다고 생각합니다. – svick

+0

@svick, 나는'Task.FromResult (true)'가 더 적절하다고 동의하지만'millisecondsDelay' 만 변경하여 동기화와 비동기를 쉽게 시뮬레이션 할 수 있으므로'Task.Delay (millisecondsDelay : 0) '를 여전히 좋아한다. 그들이이 행동을 바꿀 수도 있다고 생각합니까? 그것은 위의 코드를 제공하면서 나를위한 급격한 변화처럼 보일 것입니다. – Noseratio

관련 문제