C# Task.wait可等待项的任何功能
由于在异步函数中等待了0.25秒,我当前正处于竞争状态。取消令牌在循环中检查,但由于等待而延迟 我正在使用一个提供“wait.Until”功能的库,它允许等待布尔值。因此,我考虑等待0.25秒,或者token.isCancelled为true 我确信,将它们外包到单独的任务中,然后使用Task.waitAny()会起作用,但这似乎有点过头了。有没有更优雅的方式来等待多个等待者C# Task.wait可等待项的任何功能,c#,asynchronous,C#,Asynchronous,由于在异步函数中等待了0.25秒,我当前正处于竞争状态。取消令牌在循环中检查,但由于等待而延迟 我正在使用一个提供“wait.Until”功能的库,它允许等待布尔值。因此,我考虑等待0.25秒,或者token.isCancelled为true 我确信,将它们外包到单独的任务中,然后使用Task.waitAny()会起作用,但这似乎有点过头了。有没有更优雅的方式来等待多个等待者 while (!Completed) { Completed = AdjustPath(); awai
while (!Completed)
{
Completed = AdjustPath();
await Await.Seconds(PathingDelay);
if (!loop)
return Completed;
else if (token.IsCancellationRequested)
{
StopMove();
return false;
}
}
上面的问题是再次调用包含函数,在取消解决之前设置目标,停止对象并删除目标。虽然我可以等待任务完成,但这会增加方法运行的延迟,这并不理想。使用,就像Dmitry在评论中已经提出的那样
while (!Completed)
{
Completed = AdjustPath();
try
{
await Task.Delay(PathingDelay, token);
}
catch(TaskCanceledException e){} // if delay was cancelled is checked in next lines
if (!loop)
return Completed;
else if (token.IsCancellationRequested)
{
StopMove();
return false;
}
}
使用
TaskCompletionSource
可以构建一个任务
,当给定的CancellationToken
请求取消时,该任务将完成
public static class Async
{
private static readonly TaskCompletionSource<bool> _neverComplete = new TaskCompletionSource<bool>();
public static Task CompleteOnCancellation( CancellationToken token )
{
if ( !token.CanBeCanceled )
return _neverComplete.Task;
if ( token.IsCancellationRequested )
return Task.CompletedTask;
var tcs = new TaskCompletionSource<bool>();
token.Register( () => tcs.SetResult( true ) );
return tcs.Task;
}
}
看看Task.Delay,它接受一个可选的CancellationToken(针对这个特定问题)任务。Delay在被取消时不会返回控制并传递等待,因此不会执行必要的中断功能。据我所知,wait不能在try-catch语句中,但task.wait可以(尽管会阻塞线程)。我不确定这是否行得通,但我稍后会尝试一下。Wait可能从C#6开始就处于catch块中,并且可能始终处于try块中。根据文档,您确实是正确的。我不确定我在哪里看到它不能。可能相关:取消延迟似乎会返回整个函数,因为我相信它会引发异常。这也不理想,因为它排除了在取消时调用StopMove()。我的评估正确吗?虽然这看起来比其他解决方案更优雅,但我不确定它是否适用于此特定实例,因为似乎没有办法从令牌中删除已注册的代理,并且令牌只有在取消时才会续订。这似乎会导致将多个相同的委托分配给令牌,并运行过多的“StopMove()”调用。这不是功能上的问题,但似乎是不好的做法。然而,在任务链完成时更新令牌可能是可行的。这不会给我的大脑带来任何问题。
using var cts = new CancellationTokenSource( 100 );
var longWaitingTask = Task.Delay( 250 );
var cancellationTask = Async.CompleteOnCancellation( cts.Token );
var completedTask = await Task.WhenAny( longWaitingTask, cancellationTask );
if ( completedTask == longWaitingTask )
{
Console.WriteLine( "Long Running Task completed." );
}
if ( completedTask == cancellationTask )
{
Console.WriteLine( "Cancellation Task completed." );
}