Task.Delay for more than int.MaxValue milliseconds

The maximum duration of a Task.Delay can be indicated by a delay of int.MaxValue milliseconds. What is the cleanest way to create a Task that will be delayed during this time?

 // Fine. await Task.Delay(TimeSpan.FromMilliseconds(int.MaxValue)); // ArgumentOutOfRangeException await Task.Delay(TimeSpan.FromMilliseconds(int.MaxValue + 1L)); 
+7
c # task-parallel-library async-await
source share
5 answers

You cannot achieve this with a single Task.Delay , as it internally uses System.Threading.Timer , which accepts only int.

However, you can do this using several expectations one by one. Here's the cleanest way:

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

You can easily write a method to break it into smaller delays:

 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); } 
+2
source share

If you need precision, you should use Stopwatch instead of allocating delay to Int16.MaxValue pieces. Here's how the code below is different from the other answers:

  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: According to a comment by @CoryNelson, Stopwatch not good enough for long laps. If so, you can simply use 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
source share

You can not. Each overload will throw an ArgumentOutOfRange exception if you pass a value that will be resolved more milliseconds than Int32.MaxValue. This is true even for TimeSpan overloads ( MSDN ).

The best you could do is wait twice:

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

You can put it off several times. For example:

 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); } 

However, int.MaxValue milliseconds is a really long time, almost 25 days! IMHO a much more important question, is the Task.Delay() method really the best solution for your scenario? Knowing more about why you are trying to wait for such a long period of time can help others offer you a better solution to a real problem, instead of solving this specific need.

0
source share

All Articles