gpt4 book ai didi

c# - 取消 token 源和嵌套任务

转载 作者:行者123 更新时间:2023-11-30 14:58:27 24 4
gpt4 key购买 nike

我对我正在使用的取消 token 源有疑问,如下面的代码所示:

    void Process()
{
//for the sake of simplicity I am taking 1, in original implementation it is more than 1
var cancellationToken = _cancellationTokenSource.Token;
Task[] tArray = new Task[1];
tArray[0] = Task.Factory.StartNew(() =>
{
cancellationToken.ThrowIfCancellationRequested();
//do some work here
MainTaskRoutine();
}, cancellationToken);

try
{
Task.WaitAll(tArray);
}
catch (Exception ex)
{
//do error handling here
}
}

void MainTaskRoutine()
{
//for the sake of simplicity I am taking 1, in original implementation it is more than 1
//this method shows that a nested task is created
var cancellationToken = _cancellationTokenSource.Token;
Task[] tArray = new Task[1];
tArray[0] = Task.Factory.StartNew(() =>
{
cancellationToken.ThrowIfCancellationRequested();
//do some work here

}, cancellationToken);

try
{
Task.WaitAll(tArray);
}
catch (Exception ex)
{
//do error handling here
}
}


编辑:进一步阐述

最终目标是:当用户取消操作时,所有立即挂起的任务(无论是子任务还是孙子任务)都应该取消。

场景:按照上面的代码:1.我首先检查用户是否要求取消2. 如果用户未要求取消,则仅继续执行任务(请参阅处理方法)。示例代码在这里只显示了一个任务,但实际上可以有三个或更多

假设 CPU 开始处理 Task1,而其他任务仍在任务队列中等待某个 CPU 来执行它们。用户请求取消:Process 方法中的 Task 2,3 立即取消,但 Task 1 将继续工作,因为它已经在处理中。

在任务 1 中,它调用方法 MainTaskRoutine,后者又创建更多任务。

在 MainTaskRoutine 的函数中我写了: cancellationToken.ThrowIfCancellationRequested();

所以问题是:它是使用 CancellationTokenSource 的正确方法吗,因为它依赖于 Task.WaitAll()?

最佳答案

[已编辑] 当您在代码中使用数组时,我假设可能有多个任务,而不仅仅是一个。我还假设在您从 Process 开始的每个任务中,您希望首先执行一些 CPU 密集型工作(//do some work here),然后运行MainTaskRoutine

您如何处理任务取消异常取决于您的项目设计工作流程。例如,您可以在 Process 方法内或从您调用 Process 的地方执行此操作。如果您唯一关心的是从跟踪未决任务的数组中删除 Task 对象,可以使用 Task.ContinueWith 来完成。 .无论任务的完成状态如何(CancelledFaultedRanToCompletion)都将执行延续:

Task Process(CancellationToken cancellationToken)
{
var tArray = new List<Task>();
var tArrayLock = new Object();

var task = Task.Run(() =>
{
cancellationToken.ThrowIfCancellationRequested();
//do some work here

return MainTaskRoutine(cancellationToken);
}, cancellationToken);

// add the task to the array,
// use lock as we may remove tasks from this array on a different thread
lock (tArrayLock)
tArray.Add(task);
task.ContinueWith((antecedentTask) =>
{
if (antecedentTask.IsCanceled || antecedentTask.IsFaulted)
{
// handle cancellation or exception inside the task
// ...
}
// remove task from the array,
// could be on a different thread from the Process's thread, use lock
lock (tArrayLock)
tArray.Remove(antecedentTask);
}, TaskContinuationOptions.ExecuteSynchronously);

// add more tasks like the above
// ...

// Return aggregated task
Task[] allTasks = null;
lock (tArrayLock)
allTasks = tArray.ToArray();
return Task.WhenAll(allTasks);
}

您的 MainTaskRoutine 可以采用与 Process完全相同的方式构建,并且具有相同的方法签名(返回一个 Task )。

然后您可能希望对 Process 返回的聚合任务执行阻塞等待,或异步处理其完成,例如:

// handle the completion asynchronously with a blocking wait
void RunProcessSync()
{
try
{
Process(_cancellationTokenSource.Token).Wait();
MessageBox.Show("Process complete");
}
catch (Exception e)
{
MessageBox.Show("Process cancelled (or faulted): " + e.Message);
}
}

// handle the completion asynchronously using ContinueWith
Task RunProcessAync()
{
return Process(_cancellationTokenSource.Token).ContinueWith((task) =>
{
// check task.Status here
MessageBox.Show("Process complete (or cancelled, or faulted)");
}, TaskScheduler.FromCurrentSynchronizationContext());
}

// handle the completion asynchronously with async/await
async Task RunProcessAync()
{
try
{
await Process(_cancellationTokenSource.Token);
MessageBox.Show("Process complete");
}
catch (Exception e)
{
MessageBox.Show("Process cancelled (or faulted): " + e.Message);
}
}

关于c# - 取消 token 源和嵌套任务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18946775/

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