gpt4 book ai didi

c# - 如何使用 CancellationToken 安全地取消任务并等待 Task.WhenAll

转载 作者:太空宇宙 更新时间:2023-11-03 21:20:52 26 4
gpt4 key购买 nike

我有一个框架,它创建一个 CancellationTokenSource,配置 CancelAfter,然后调用一个异步方法并传递 token 。 async 方法然后生成许多任务,将取消 token 传递给它们中的每一个,然后等待任务的收集。这些任务每个都包含通过轮询 IsCancellationRequested 正常取消的逻辑。

我的问题是,如果我将 CancellationToken 传递给 Task.Run(),则会抛出包含 TaskCanceledException 的 AggregateException。这会阻止任务正常取消。

为了解决这个问题,我无法将 CancellationToken 传递给 Task.Run,​​但是我不确定我会丢失什么。例如,我喜欢这样的想法,即如果我的任务挂起并且无法执行优雅的取消,这个异常将强制它停止。我在想我可以串起两个 CancellationTokens 来处理这个问题,一个是“优雅的”,另一个是“强制的”。但是,我不喜欢这种解决方案。

这是代表我上面描述的一些伪代码..

public async Task Main()
{
CancellationTokenSource cts = new CancellationTokenSource();
cts.CancelAfter(30000);
await this.Run(cts.Token);
}

public async Task Run(CancellationToken cancelationToken)
{
HashSet<Task> tasks = new HashSet<Task>();
foreach (var work in this.GetWorkNotPictured)
{
// Here is where I could pass the Token,
// however If I do I cannot cancel gracefully
// My dilemma here is by not passing I lose the ability to force
// down the thread (via exception) if
// it's hung for whatever reason
tasks.Add(Task.Run(() => this.DoWork(work, cancelationToken))
}

await Task.WhenAll(tasks);

// Clean up regardless of if we canceled
this.CleanUpAfterWork();

// It is now safe to throw as we have gracefully canceled
cancelationToken.ThrowIfCancellationRequested();
}

public static void DoWork(work, cancelationToken)
{
while (work.IsWorking)
{
if (cancelationToken.IsCancellationRequested)
return // cancel gracefully
work.DoNextWork();
}
}

最佳答案

我建议您遵循抛出异常而不是仅仅返回的标准取消模式:

public static void DoWork(work, cancellationToken)
{
while (work.IsWorking)
{
cancellationToken.ThrowIfCancellationRequested();
work.DoNextWork();
}
}

如果您有清理工作要做,这就是 finally 的用途(或者 using,如果您可以那样重构的话):

public async Task Run(CancellationToken cancellationToken)
{
HashSet<Task> tasks = new HashSet<Task>();
foreach (var work in this.GetWorkNotPictured)
{
tasks.Add(Task.Run(() => this.DoWork(work, cancellationToken))
}

try
{
await Task.WhenAll(tasks);
}
finally
{
this.CleanUpAfterWork();
}
}

关于c# - 如何使用 CancellationToken 安全地取消任务并等待 Task.WhenAll,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30848606/

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