【问题标题】:Restarting task if it fails如果任务失败则重新启动任务
【发布时间】:2017-10-18 01:10:42
【问题描述】:

如果失败,我正在尝试重新启动多个任务之一。我使用.ContinueWith(t => { HandleException(t); }, TaskContinuationOptions.OnlyOnFaulted);,其中HandleException(t) 方法应该在现有任务数组中找到任务并在其位置创建一个新任务。只有传递给我的 HandleException(t) 方法的任务与原始任务不同,所以我无法在我现有的任务中找到它。此外,在处理异常时,excisting 任务仍在运行。

示例:

using System;
using System.Threading.Tasks;
using System.Threading;

static Task[] tasks;
static void Main(string[] args)
{
    tasks = new Task[2];
    for (int i = 0; i < tasks.Count(); i++)
    {
        tasks[i] = Task.Run(() => { Thread.Sleep(1000); throw new Exception("BOOM"); })
             .ContinueWith(t => { HandleException(t); }
             , TaskContinuationOptions.OnlyOnFaulted);

        Console.WriteLine(String.Format("Task {0} started", tasks[i].Id));
    }

    Console.ReadLine();
}

static void HandleException(Task task)
{
    Console.WriteLine(String.Format("Task {0} stopped", task.Id));

    // Check task status
    for (int i = 0; i < tasks.Count(); i++)
    {
        Console.WriteLine(String.Format("Task {0} status = {1}", i, tasks[i].Status));
    }
    // fFind and restart the task here
    if (tasks.Contains(task))
    {
        int index = Array.IndexOf(tasks, task);
        tasks[index] = Task.Run(() => { Thread.Sleep(1000); throw new Exception("BOOM"); })
         .ContinueWith(t => { HandleException(t); }
         , TaskContinuationOptions.OnlyOnFaulted);

        Console.WriteLine(String.Format("Task {0} started", tasks[index].Id));
    }
}

我的申请结果:

Task 3 started
Task 6 started
Task 5 stopped
Task 0 status = Running
Task 2 stopped
Task 1 status = Running
Task 0 status = Running
Task 1 status = Running

由于传递给HandleException(t)的任务与原来的任务不同,所以在tasks[]中没有找到,因此没有重启。还要查看tasks[] 的状态,它还没有停止。如何正确重启我的任务?

【问题讨论】:

    标签: c# task continuations


    【解决方案1】:

    这是因为您将延续任务存储在数组中,而不是原始任务(即 - 您存储 ContinueWith 的结果)。要修复,请改为存储原始任务:

    var task = Task.Run(() => { Thread.Sleep(1000); throw new Exception("BOOM");});
    task.ContinueWith(t => { HandleException(t); }
             , TaskContinuationOptions.OnlyOnFaulted);
    tasks[i] = task;
    

    【讨论】:

    • 太棒了,这确实是问题所在。它还修复了任务状态。
    • @Evk 既然 HandleException(t) 是递归调用,那它最终不会引入堆栈溢出吗?
    • @MaximPodkolzin 不,因为所有这些都发生在不同的线程上。新任务通过Task.Run 启动,这会从线程池中抓取一个线程 > 抛出异常 > 调用 HandleException,可能会再次在不同的线程上 > 再次调用 Task.Run 并从线程池中抓取另一个线程(同样不能因为它正忙于执行 HandleException) > 当前线程完成执行并返回池。对于堆栈溢出,同一个线程应该递归执行函数,但这里我们有不同的线程(因此不同的堆栈)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-09-02
    • 1970-01-01
    • 2017-01-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多