Task.Delay超过int.MaxValue毫秒

时间:2015-01-17 01:26:31

标签: c# .net task-parallel-library async-await

可以告诉Task.Delay延迟的最长持续时间是int.MaxValue毫秒。创建Task的最简洁方法是什么,这会延迟超过那个时间?

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

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

5 个答案:

答案 0 :(得分:10)

使用单个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;
    }
}

答案 1 :(得分:3)

您可以轻松编写一种方法将其细分为较小的延迟:

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 :(得分:1)

您可以延迟多次。例如:

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毫秒是真的长时间,差不多25天!恕我直言,一个更重要的问题是,Task.Delay()方法真的是你的方案的最佳解决方案吗?了解更多关于为什么要等待这么长时间的原因可能会帮助其他人为实际问题提供更好的解决方案,而不是解决这个非常具体的需求。

答案 3 :(得分:1)

如果您关心精确度,则应使用Stopwatch而不是delay Int16.MaxValue块。 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)); } } 。以下代码与其他答案的不同之处如下:

Stopwatch

更新:根据@ CoryNelson的评论,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}}

答案 4 :(得分:0)

你做不到。如果传递一个可以解析为比Int32.MaxValue更多毫秒的值,则每个重载都将抛出ArgumentOutOfRange异常。即使TimeSpan重载(MSDN)也是如此。

你能做的最好是等待两次:

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