- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我有一个交互式任务,在“最坏”的情况下根本不会执行,因此它由 TaskCompletionSource
表示。
我想等待这个任务完成,或者我收到的 token 被取消——以先发生者为准。 Task.WhenAny
是完成此类工作的完美工具,唯一的问题是它只接受任务,而我有一个 Task
和一个 CancellationToken
。
如何等待(异步,如 Task.WhenAny
)第一个事件触发——完成的任务,或取消的 token ?
async Task MyCodeAsync(CancellationToken token)
{
var tcs = new TaskCompletionSource<UserData>(); // represents interactive part
await Task.WhenAny(tcs.Task, token); // imaginary call
UserData data = tcs.Task.Result; // user interacted, let's continue
...
}
我不创建/管理 token ,因此我无法更改它。我必须处理它。
更新:对于这种特殊情况,可以在 token 上使用Register
方法来取消TaskCompletionSource
。有关更通用的方法,请参阅 Matthew Watson 的回答。
最佳答案
您可以创建一个额外的任务,当取消 token 的等待句柄发出信号时返回:
var factory = new CancellationTokenSource();
var token = factory.Token;
await Task.WhenAny(
Task.Run(() => token.WaitHandle.WaitOne()),
myTask());
(但是,请注意,这虽然简单,但确实会占用一个额外的线程,这显然不理想。稍后请参阅不使用额外线程的替代解决方案。)
如果你想检查哪个任务完成了,你必须在调用 WhenAny()
之前保留任务的副本,这样你就可以将它们与返回值进行比较,例如:
using System;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApp1
{
class Program
{
static async Task Main()
{
var factory = new CancellationTokenSource(1000); // Change to 3000 for different result.
var token = factory.Token;
var task = myTask();
var result = await Task.WhenAny(
Task.Run(() => token.WaitHandle.WaitOne()),
task);
if (result == task)
Console.WriteLine("myTask() completed");
else
Console.WriteLine("cancel token was signalled");
}
static async Task myTask()
{
await Task.Delay(2000);
}
}
}
如果您不想浪费整个线程等待取消 token 发出信号,您可以使用 CancellationToken.Register()
注册一个回调,您可以使用该回调设置一个 TaskCompletionSource
:
( Lifted from here )
public static Task WhenCanceled(CancellationToken cancellationToken)
{
var tcs = new TaskCompletionSource<bool>();
cancellationToken.Register(s => ((TaskCompletionSource<bool>) s).SetResult(true), tcs);
return tcs.Task;
}
然后您可以按如下方式使用它:
using System;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApp1
{
class Program
{
static async Task Main()
{
var factory = new CancellationTokenSource(1000);
var token = factory.Token;
var task = myTask();
var result = await Task.WhenAny(
WhenCanceled(token),
task);
if (result == task)
Console.WriteLine("myTask() completed");
else
Console.WriteLine("cancel token was signalled");
}
public static Task WhenCanceled(CancellationToken cancellationToken)
{
var tcs = new TaskCompletionSource<bool>();
cancellationToken.Register(s => ((TaskCompletionSource<bool>) s).SetResult(true), tcs);
return tcs.Task;
}
static async Task myTask()
{
await Task.Delay(2000);
}
}
}
对于一般情况,这是一种更可取的方法。
关于c# - 如何获得 Task.WhenAny 对 Task 和 CancellationToken 的影响?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57868078/
我有一个控制台应用程序,我在其中使用 TPL,当我在任务中点击 whenany 时它会退出。我是线程的新手,有人可以指导我正确的方向吗(我单独执行了 RunJob,它没有异常(exception))。
当将多个已完成的任务传递给 Task.WhenAny 时,Task.WhenAny 会优先选择将返回哪个已完成的任务? 最佳答案 当您想知道确切的行为时,通常可以查看 reference source
考虑一个具有某种生命周期的类。在此生命周期中,一个事件可能会发生任意多次,并且该事件是通过完成任务(在事件发生后更新)来发出信号的。该对象也可能被关闭,结束其生命周期。关闭也通过完成任务发出信号。它也
我有这段代码: var client = new TcpClient(); HttpRequestInfo.AddTimestamp("Connecting"); await Task.WhenAny
我在 ReactiveLists 中保存了一些检查列表,它们具有 ChangeTrackingEnabled = true。我只想在每个列表中至少选中一个项目时才启用我的 OkCommand。 此外,
在下面的代码中: if (await Task.WhenAny(task, Task.Delay(100)) == task) { success = true
我想同时执行多个异步任务。每个任务将运行一个 HTTP 请求,该请求可以成功完成或引发异常。我需要等待直到第一个任务成功完成,或者直到所有任务都失败。 如何实现 Task.WhenAny 的重载接受谓
当我使用 Task.WhenAll() 函数并在任务中抛出异常时,会抛出一个新的 AggregateException,我可以捕获它以查看任务中发生的所有异常。但是,当我使用 Task.WhenAny
在我的应用程序中,我正在创建一些并发的网络请求,当其中任何一个完成时我都很满意,所以我使用了方法 Task.WhenAny : var urls = new string[] { "https
假设我有三个任务,a、b 和 c。这三个都保证在 1 到 5 秒之间的随机时间抛出异常。然后我写了下面的代码: await Task.WhenAny(a, b, c); 这最终会从最先出错的任务中抛出
我有以下代码: List> tasks = tasksQuery.ToList(); while (tasks.Any()) { Task completedTask = await Task
我需要为移动应用程序中的任务调用添加超时功能。我尝试使用 Task.WhenAny 来完成此操作,如下所示。这将返回首先完成的任务。我的问题是,最初我是从这个任务中获取返回值的,如果任务没有超时,我仍
我有以下代码片段来处理 Azure 通知中心推送通知: var alert = "{\"aps\":{\"alert\":\"" + message + "\"}}"; var task = Azur
我有一个带有两个 WhenAnyValues 的对象: this.WhenAnyValue(x => x.SomeInt) .Select(x => "Bar" + x) .ToPro
我的解决方案中有两个项目:WPF 项目和类库。 在我的类库中: 我有一个符号列表: class Symbol { Identifier Identifier {get;set;}
我有一个带有两个 WhenAnyValues 的对象: this.WhenAnyValue(x => x.SomeInt) .Select(x => "Bar" + x) .ToPro
我如何并行运行 2 个任务并在一个特定任务结束时得到通知(在我的例子中是列表中的第一个任务) 目前我正在使用这段代码: await Task.WhenAny(A.Play(cancel), B.Pla
我有一个创建多个基于 I/O 的任务的解决方案,我正在使用 Task.WhenAny() 来管理这些任务。但往往很多任务会因为网络问题或请求节流等原因而失败。 在使用 Task.WhenAny() 方
考虑在 ReactiveUI 中使用继承。我有带有 DoSomethingCommand 的 ViewModel 基类。此命令的“CanExecute”取决于属性 Prop1 public class
Reactive UI 中有几种扩展方法可用于获取属性更改的 observable。 我想我明白 WhenAny和 WhenAnyValue . WhenAny用于一系列属性更改通知,您希望其中的对象
我是一名优秀的程序员,十分优秀!