gpt4 book ai didi

c# - 如何让 Task.Delay 提前完成

转载 作者:行者123 更新时间:2023-12-04 00:13:25 25 4
gpt4 key购买 nike

我的代码正在等待一些时间延迟:

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/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com