Asynchronously wait for Task to complete with timeout

后端 未结 16 2019
天命终不由人
天命终不由人 2020-11-21 17:49

I want to wait for a Task to complete with some special rules: If it hasn\'t completed after X milliseconds, I want to display a message to the user. And

16条回答
  •  长发绾君心
    2020-11-21 18:45

    I felt the Task.Delay() task and CancellationTokenSource in the other answers a bit much for my use case in a tight-ish networking loop.

    And although Joe Hoag's Crafting a Task.TimeoutAfter Method on MSDN blogs was inspiring, I was a little weary of using TimeoutException for flow control for the same reason as above, because timeouts are expected more frequently than not.

    So I went with this, which also handles the optimizations mentioned in the blog:

    public static async Task BeforeTimeout(this Task task, int millisecondsTimeout)
    {
        if (task.IsCompleted) return true;
        if (millisecondsTimeout == 0) return false;
    
        if (millisecondsTimeout == Timeout.Infinite)
        {
            await Task.WhenAll(task);
            return true;
        }
    
        var tcs = new TaskCompletionSource();
    
        using (var timer = new Timer(state => ((TaskCompletionSource)state).TrySetCanceled(), tcs,
            millisecondsTimeout, Timeout.Infinite))
        {
            return await Task.WhenAny(task, tcs.Task) == task;
        }
    }
    
    
    

    An example use case is as such:

    var receivingTask = conn.ReceiveAsync(ct);
    
    while (!await receivingTask.BeforeTimeout(keepAliveMilliseconds))
    {
        // Send keep-alive
    }
    
    // Read and do something with data
    var data = await receivingTask;
    

    提交回复
    热议问题