如何监视和重新启动在C#中引发异常的任务?
假设我有一个程序,它实例化了三个无限期运行的任务。这些任务旨在并行运行。但是,假设这些任务由于网络错误而偶尔抛出异常 监视任务并在必要时重新启动它的最简单技术是什么 解决这个问题的方法是监视Task.Status数据,如果任务出现故障,只需调用Task.Start()方法 但是,此代码不起作用,因为任务的异常会导致整个应用程序崩溃如何监视和重新启动在C#中引发异常的任务?,c#,.net,asynchronous,async-await,C#,.net,Asynchronous,Async Await,假设我有一个程序,它实例化了三个无限期运行的任务。这些任务旨在并行运行。但是,假设这些任务由于网络错误而偶尔抛出异常 监视任务并在必要时重新启动它的最简单技术是什么 解决这个问题的方法是监视Task.Status数据,如果任务出现故障,只需调用Task.Start()方法 但是,此代码不起作用,因为任务的异常会导致整个应用程序崩溃 using System; using System.Collections.Generic; using System.Linq; using System.Tex
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
var my_task = Program.MainAsync();
my_task.Wait();
}
public static async Task MainAsync()
{
var task_1 = Program.TaskMethod("1");
var task_2 = Program.TaskMethod("2");
var task_3 = Program.TaskMethod("3");
// loop indefinitely restarting task if necessary
while(true)
{
if (task_1.Status == TaskStatus.Faulted)
task_1.Start();
if (task_2.Status == TaskStatus.Faulted)
task_2.Start();
if (task_3.Status == TaskStatus.Faulted)
task_3.Start();
await Task.Delay(1000);
}
}
public static async Task TaskMethod(string task_id)
{
Console.WriteLine("Starting Task {0}", task_id);
while(true)
{
await Task.Delay(5000);
Console.WriteLine("Hello from task {0}", task_id);
int i = 0;
int b = 32 / i;
}
}
}
}
如果线程出现异常,我的应用程序也会崩溃。 所以我学会了总是在任何线程或任务方法中添加try/catch。 此外,异常消息还有助于调试/改进程序 我只想:
- 在任务方法中使用try-catch
- 将异常用作任务的返回值
- 使用WaitAny不要过于频繁地轮询,只在任务失败/结束时作出反应
- 此处使用SortedDictionary来标识任务及其开始参数
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
var my_task = Program.MainAsync();
my_task.Wait();
}
public static async Task MainAsync()
{
var tasks = new SortedDictionary<string, Task<Exception>>();
for (int idx = 1; idx <= 3; idx++)
{
var parameter = idx.ToString();
tasks.Add(parameter, Program.TaskMethod(parameter));
}
// loop indefinitely restarting task if necessary
while (tasks.Any())
{
var taskArr = tasks.Values.ToArray();
var finishedIdx = Task.WaitAny(taskArr, 30000);
if (0 <= finishedIdx)
{
var finishedTask = taskArr[finishedIdx];
var parameter = tasks.First(kvp => kvp.Value == finishedTask).Key;
if (finishedTask.Result != null) // exception was thrown
{
tasks[parameter] = Program.TaskMethod(parameter); // restart the task!
}
else
{
tasks.Remove(parameter);
}
}
}
}
public static async Task<Exception> TaskMethod(string task_id)
{
try
{
Console.WriteLine("Starting Task {0}", task_id);
while (true)
{
await Task.Delay(5000);
Console.WriteLine("Hello from task {0}", task_id);
int i = 0;
int b = 32 / i;
}
return null;
}
catch (Exception exc)
{
return exc;
}
}
}
}
由于无法重新启动
任务
,因此必须使用任务工厂Func
,每当任务
失败时,可以反复调用该工厂来创建更多任务
var taskFactories = new List<Func<Task>>();
taskFactories.Add(() => TaskMethod("1"));
taskFactories.Add(() => TaskMethod("2"));
taskFactories.Add(() => TaskMethod("3"));
var runningTasks = taskFactories.ToDictionary(factory => factory());
while (runningTasks.Count > 0)
{
// Wait for something to happen, good or bad
var completedTask = await Task.WhenAny(runningTasks.Keys);
if (completedTask.IsFaulted) // Something bad happened
{
var factory = runningTasks[completedTask];
var newTask = factory();
runningTasks.Remove(completedTask);
runningTasks.Add(newTask, factory);
}
else // A task just finished normally or was canceled
{
runningTasks.Remove(completedTask);
}
}
var taskFactories=new List();
taskFactorys.Add(()=>TaskMethod(“1”);
taskFactorys.Add(()=>TaskMethod(“2”));
taskFactorys.Add(()=>TaskMethod(“3”);
var runningTasks=taskFactories.ToDictionary(factory=>factory());
while(runningTasks.Count>0)
{
//等待事情发生,好的或坏的
var completedTask=wait Task.wheny(runningTasks.Keys);
if(completedTask.IsFaulted)//发生了错误
{
var factory=runningTasks[completedTask];
var newTask=factory();
runningTasks.Remove(completedTask);
runningTasks.Add(newTask,工厂);
}
else//任务刚刚正常完成或被取消
{
runningTasks.Remove(completedTask);
}
}
您无法“重新启动”任务。为什么不捕获任务中的异常,并让任务本身循环?顺便说一句,假设您使用的是C#7+,您可能希望使用公共静态异步任务Main
和Wait Program.MainAsync
而不是使用.Wait()
。否则仙女就会失去翅膀;)非常好地使用了factory,这是高效重启机制的核心+1这似乎有效,但我不理解“var runningTasks=taskFactories.ToDictionary(factory=>factory())”。为什么需要将列表转换为字典?factory()方法定义在哪里?@IzzoToDictionary
在当前运行的任务和它们的工厂之间创建一个映射,以便在出现异常时可以找到正确的工厂,然后再次调用。工厂方法是存储在taskFactories
列表中的lambda,也作为值存储在字典中。例如,()=>TaskMethod(“1”)
是一个工厂。调用时,它会创建一个新任务。很好,不过请看-if(0谢谢这个新术语。Yoda的讲话是一个品味问题。我从一本“代码完成”的书中得到了它,看起来Microsoft使用过一次。没问题。:)是的,完全可能。一切都很好,先生!
var taskFactories = new List<Func<Task>>();
taskFactories.Add(() => TaskMethod("1"));
taskFactories.Add(() => TaskMethod("2"));
taskFactories.Add(() => TaskMethod("3"));
var runningTasks = taskFactories.ToDictionary(factory => factory());
while (runningTasks.Count > 0)
{
// Wait for something to happen, good or bad
var completedTask = await Task.WhenAny(runningTasks.Keys);
if (completedTask.IsFaulted) // Something bad happened
{
var factory = runningTasks[completedTask];
var newTask = factory();
runningTasks.Remove(completedTask);
runningTasks.Add(newTask, factory);
}
else // A task just finished normally or was canceled
{
runningTasks.Remove(completedTask);
}
}