如果其中一个任务出现故障,请停止执行

本文关键字:故障 执行 任务 一个 如果 | 更新日期: 2023-09-27 18:21:28

我有一个关于TPL任务的问题。我有一些任务是"显示停止程序",一旦其中一个出现故障,我不希望该方法继续运行,但给出一个异常并退出。我试着使用TaskContinuationOptions,类似这样的东西:

var res = Task.Factory.ContinueWhenAny(
            new[] { task1, task2, task3},
                    task =>
                    {
                        throw task.Exception.Flatten();
                    },
                    CancellationToken.None,
                    TaskContinuationOptions.OnlyOnFaulted,
                    this.taskScheduler);
var res1 = Task.Factory.ContinueWhenAll(
                    new[] { task1, task2, task3},
                    tasks =>
                    {
                        // DO SOME CODE
                    },
                    CancellationToken.None,
                    TaskContinuationOptions.NotOnFaulted,
                    this.taskScheduler);
return Task.WhenAny(res, res1).Unwrap();

但不幸的是,当继续执行多个任务时,TaskContinuationOptions的过滤会受到限制。解决这个问题的办法是什么?

如果其中一个任务出现故障,请停止执行

您可以实现一个循环,在任务完成时检查任务是否出现故障。如果其中一个出现故障,您可以抛出并退出方法:

List<Task> tasks = new List<Task> {task1, task2, task3}; // Show stopping tasks.
while (tasks.Count > 0)
{
    var finishedTask = await Task.WhenAny(tasks);
    tasks.Remove(finishedTask);
    if (finishedTask.Status == TaskStatus.Faulted)
    {
        // Throw and exit the method.
    }
}
// Continuation code goes here.

请注意,这不会取消其他正在进行的任务。如果需要,可以使用CancellationToken实现取消机制,并显式取消剩余任务。您的任务需要通过查看CancellationToken.IsCancellationRequested属性或使用CancellationToken.ThrowIfCancellationRequested方法来监控取消令牌,以查看是否有取消请求:

var cts = new CancellationTokenSource();
     // Generate some tasks for this example.
var task1 = Task.Run(async () => await Task.Delay(1000, cts.Token), cts.Token);
var task2 = Task.Run(async () => await Task.Delay(2000, cts.Token), cts.Token);
var task3 = Task.Run(async () => await Task.Delay(3000, cts.Token), cts.Token);
List<Task> tasks = new List<Task> {task1, task2, task3};
while (tasks.Count > 0)
{
    var finishedTask = await Task.WhenAny(tasks);
    tasks.Remove(finishedTask);
    if (finishedTask.Status == TaskStatus.Faulted)
    {
        cts.Cancel();
        // Throw and exit the method.
    }
}

您可以使用CancellationTokenSource并使用此取消令牌运行所有任务,因此如果令牌被取消,则其他任务也将被取消

      var cs = new CancellationTokenSource();
      var options = new ParallelOptions { CancellationToken = cs.Token };
      var array = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
      try
      {
          Parallel.ForEach(array, options, (index) =>
          {
              CallCustomMethod(cs, index);
          });
      }
      catch (OperationCanceledException ex)
      { 
      }
     void CallCustomMethod(CancellationTokenSource cs, int index)  
     {   
        try
        {
            if (cs.IsCancellationRequested)
            {
                return;
            }
            if (index == 4)
            {
                throw new Exception("Cancel");
            }
            Console.WriteLine(index);
        }
        catch
        {
            cs.Cancel();
        }
    }