2015-01-17 5 views
7

Task.Delay의 지연 지속 시간은 int.MaxValue 밀리 초입니다. 그 시간 이상으로 지연되는 Task을 만드는 가장 깨끗한 방법은 무엇입니까?int.MaxValue 밀리 초를 초과하는 작업. 지연

// Fine. 
await Task.Delay(TimeSpan.FromMilliseconds(int.MaxValue)); 

// ArgumentOutOfRangeException 
await Task.Delay(TimeSpan.FromMilliseconds(int.MaxValue + 1L)); 
+4

난 당신을 위해 ... (확인 계산기) ... 24.86 일 무언가를 지연 싶어하는 상황을 추측 할 수 없습니다. –

+0

기다리는 데는 25 일이 걸립니다. 영원히 기다리고 싶다면'Task.Delay (-1) '를 사용할 수 있습니다. – i3arnon

+0

@ DanielMann 주어진 기간 후에 엔트리를 제거하는 캐시를 쓰고 있습니다. 오랫동안 캐시하려는 사람은 거의 없을 것 같지만 제한적인 요소가되기를 원하지는 않습니다. –

답변

8

Task.Delay은 내부적으로 int를 허용하는 System.Threading.Timer을 사용하기 때문에 단일 문자를 사용하여이를 구현할 수 없습니다.

하지만 여러 차례 기다리면됩니다. 여기에 가장 깨끗한 방법이있다 :

static async Task Delay(long delay) 
{ 
    while (delay > 0) 
    { 
     var currentDelay = delay > int.MaxValue ? int.MaxValue : (int) delay; 
     await Task.Delay(currentDelay); 
     delay -= currentDelay; 
    } 
} 
0

수 없습니다. 모든 오버로드는 예외를 throw합니다. Int32.MaxValue보다 큰 밀리 초 수가되는 값을 전달하면 예외가 발생합니다. TimeSpan 과부하 (MSDN)의 경우에도 마찬가지입니다.

당신이 할 수있는 가장 좋은 두 번 기다리고있다 :

await Task.Delay(TimeSpan.FromMilliseconds(int.MaxValue)); 
await Task.Delay(TimeSpan.FromMilliseconds(20)); 
+0

그것도'ArgumentOutOfRangeException'을 던집니다. –

2

쉽게 작은 지연으로 그것을 무너 뜨리는 방법을 쓸 수 있습니다 :

private static readonly TimeSpan FullDelay = TimeSpan.FromMilliseconds(int.MaxValue); 

private static async Task LongDelay(TimeSpan delay) 
{ 
    long fullDelays = delay.Ticks/FullDelay.Ticks; 
    TimeSpan remaining = delay; 
    for(int i = 0; i < fullDelays; i++) 
    { 
     await Task.Delay(FullDelay); 
     remaining -= FullDelay; 
    } 

    await Task.Delay(remaining); 
} 
0

여러 번 지연시킬 수 있습니다. 예를 들어 :

말했다
static async Task LongDelay(long milliseconds) 
{ 
    if (milliseconds < 0) 
    { 
     throw new ArgumentOutOfRangeException(); 
    } 

    if (milliseconds == 0) 
    { 
     return; 
    } 

    int iterations = (milliseconds - 1)/int.MaxValue; 

    while (iterations-- > 0) 
    { 
     await Task.Delay(int.MaxValue); 
     milliseconds -= int.MaxValue; 
    } 

    await Task.Delay(milliseconds); 
} 

int.MaxValue 밀리 초는 정말 거의 이십오일 오랜 시간 입니다! IMHO 훨씬 더 중요한 질문은 Task.Delay() 메서드가 실제로 시나리오에 가장 적합한 솔루션인가? 왜 오랜 시간 동안 기다리려고하는지 더 많이 알면 다른 사람이 실제 문제에 대한 더 나은 해결책을 제공 할 수 있습니다.

1

당신은 정밀 걱정하는 경우에, 당신은 Int16.MaxValue 덩어리로 delay을 deviding보다는 Stopwatch를 사용한다. 이것은 아래의 코드가 다른 답변 다른 방법은 다음과 같습니다

private static async Task LongDelay(TimeSpan delay) 
    { 
     var st = new System.Diagnostics.Stopwatch(); 
     st.Start(); 
     while (true) 
     { 
      var remaining = (delay - st.Elapsed).TotalMilliseconds; 
      if (remaining <= 0) 
       break; 
      if (remaining > Int16.MaxValue) 
       remaining = Int16.MaxValue; 
      await Task.Delay(TimeSpan.FromMilliseconds(remaining)); 
     } 
    } 

UPDATE : @ CoryNelson의 의견에 따르면, Stopwatch 긴 랩 충분하지 않습니다. 그렇다면, 단순히 DateTime.UtcNow를 사용하는 것이 가능하다 :

private static async Task LongDelay(TimeSpan delay) 
    { 
     var start = DateTime.UtcNow; 
     while (true) 
     { 
      var remaining = (delay - (DateTime.UtcNow - start)).TotalMilliseconds; 
      if (remaining <= 0) 
       break; 
      if (remaining > Int16.MaxValue) 
       remaining = Int16.MaxValue; 
      await Task.Delay(TimeSpan.FromMilliseconds(remaining)); 
     } 
    } 
+1

시스템 날짜/시간 (및 그 조정)의 영향을받지 않기 때문에, 스톱워치는 시스템의 시계가 부정확 해져 일정 정도의 비뚤어 짐을 나타냅니다.오랜 시간 동안 측정하기위한 것이 아닙니다. –

+0

@CoryNelson, 흥미 롭다. 나는'Stopwatch'의 그러한 단점에 대해 몰랐다. 이걸 확인하는 소식통 좀 들려 주시겠습니까? 어쨌든,'DateTime.UtcNow'를 사용하는 것은 충분히 신뢰할 만하다. 나는 코드를 업데이트했다. – avo

+1

[QueryPerformanceCounter] (http://msdn.microsoft.com/en-us/library/windows/desktop/dn553408.aspx) 문서를 참조하십시오. 링크가 쉽지는 않지만 "누적 된 오류"를 검색하십시오. 그것은 스톱워치가 무대 뒤에서 사용하는 것입니다. –

관련 문제