Dot-Net
canceltoken 超時與 task.delay() 和超時
我想執行一個應該在 n 毫秒後超時的操作。我已經實現了兩種方式,一種是在等待 n 毫秒後自己取消操作,另一種是傳入一個設置為在 n 毫秒後過期的 CancellationToken。
我擔心當我的系統負載過重時,cancellationtoken 可能會在操作開始之前過期。似乎如果我自己使用 Task.Delay() 實現超時,那麼在我的操作開始之前,Delay() 呼叫將不會執行。
這是我的做法:
public static async Task<T> TimeoutAfter<T>(this Task<T> task, TimeSpan timeout) { Task completedTask = await Task.WhenAny(task, Task.Delay(timeout)); if (completedTask == task) { return await task; } throw new TimeoutException(); } // Use it like this await SomeOperationAsync().TimeoutAfter(TimeSpan.FromMilliseconds(n));相比:
CancellationTokenSource source = new CancellationTokenSource(TimeSpan.FromMilliseconds(n)); await SomeOperationAsync(source.Token);
我不確定你的擔心是否合理,但我會假設它是合理的。
您使用的程式碼的問題
Task.Delay()是您實際上並沒有取消操作。這可能意味著您在浪費資源或誤導使用者(您告訴他們操作已超時,而操作仍在執行並且很可能會成功完成)。現在,如果您想確保取消令牌僅在操作開始後才開始計時,請執行以下操作:
var source = new CancellationTokenSource(); var task = SomeOperationAsync(source.Token); source.CancelAfter(TimeSpan.FromMilliseconds(n)); await task;如果您經常這樣做,您可能希望將此邏輯封裝到一個方法中(可能需要一個更好的名稱):
public static async Task WithTimeoutAfterStart( Func<CancellationToken, Task> operation, TimeSpan timeout) { var source = new CancellationTokenSource(); var task = operation(source.Token); source.CancelAfter(timeout); await task; }用法:
await WithTimeoutAfterStart( ct => SomeOperationAsync(ct), TimeSpan.FromMilliseconds(n));