作者热门文章
- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我的代码正在等待一些时间延迟:
await Task.Delay(10_000, cancellationToken);
在某些情况下,即使超时尚未到期,我也想立即继续(“快捷方式延迟”)。当代码已经在等待延迟时,可以做出这个决定。
我不想做的:循环条件
foreach (var i = 0; i < 10 && !continueImmediately; i++)
{
await Task.Delay(1000, cancellationToken);
}
因为它要么有一些延迟(这里是 1 秒),要么会不必要地唤醒。
我也不想做的事:取消
var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken)
try
{
await Task.Delay(1000, linkedTokenSource.Token);
}
catch (OperationCancelledException)
{
// determine if the delay was cancelled by the cancellationToken or by the delay shortcut...
}
因为我想避免异常。
我的想法:
TaskCompletionSource tcs = new TaskCompletionSource();
await Task.WhenAny(new[] { tcs.Task, Task.Delay(10_000, cancellationToken) });
并缩短延迟:tcs.SetResult()
.
这似乎可行,但我不确定是否缺少任何清理。例如。如果使用快捷方式(即由于 tcs.Task
而完成了WhenAny),Task.Delay
是否会继续消耗资源?
注意:我当然喜欢取消支持,但这不是我的问题,所以您可以忽略我问题中的所有取消 token 。
最佳答案
您可以编写自己的 Delay()
,它不会抛出仿照 Task.Delay()
实现的异常方法。
这是一个示例,如果取消 token 被取消,则返回 true
,否则返回 false
(并且延迟正常超时)。
// Returns true if cancelled, false if not cancelled.
public static Task<bool> DelayWithoutCancellationException(int delayMilliseconds, CancellationToken cancellationToken)
{
var tcs = new TaskCompletionSource<bool>();
var ctr = default(CancellationTokenRegistration);
Timer timer = null;
timer = new Timer(_ =>
{
ctr.Dispose();
timer.Dispose();
tcs.TrySetResult(false);
}, null, Timeout.Infinite, Timeout.Infinite);
ctr = cancellationToken.Register(() =>
{
timer.Dispose();
tcs.TrySetResult(true);
});
timer.Change(delayMilliseconds, Timeout.Infinite);
return tcs.Task;
}
那么你可以使用复合取消源有两种方式取消它:
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
namespace MultitargetedConsole
{
class Program
{
static async Task Main()
{
await test();
}
static async Task test()
{
const int CANCEL1_TIMEOUT = 5000;
const int CANCEL2_TIMEOUT = 2000;
const int DELAY_TIMEOUT = 10000;
using var tokenSource1 = new CancellationTokenSource(CANCEL1_TIMEOUT);
using var tokenSource2 = new CancellationTokenSource();
using var compositeTokenSource = CancellationTokenSource.CreateLinkedTokenSource(tokenSource1.Token, tokenSource2.Token);
var compositeToken = compositeTokenSource.Token;
var _ = Task.Run(() => // Simulate something else cancelling tokenSource2 after 2s
{
Thread.Sleep(CANCEL2_TIMEOUT);
tokenSource2.Cancel();
});
var sw = Stopwatch.StartNew();
bool result = await DelayWithoutCancellationException(DELAY_TIMEOUT, compositeToken);
Console.WriteLine($"Returned {result} after {sw.Elapsed}");
}
}
}
这会打印出类似 Returned True after 00:00:02.0132319
之类的内容。
如果您像这样更改超时:
const int CANCEL1_TIMEOUT = 5000;
const int CANCEL2_TIMEOUT = 3000;
const int DELAY_TIMEOUT = 2000;
结果将类似于 Returned False after 00:00:02.0188434
供引用,here is the source code对于 Task.Delay()
.
关于c# - 如何让 Task.Delay 提前完成,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66369225/
我是一名优秀的程序员,十分优秀!