c# - 以安全的方式在企业应用程序中运行多个 Task<>

标签 c# design-patterns task-parallel-library

我正在为一个产品设计软件架构,该产品可以实例化一系列“代理”来做一些有用的事情。 假设每个代理实现一个具有以下功能的接口(interface):

Task AsyncRun(CancellationToken token)

因为由于这些代理正在执行大量 I/O,所以将其作为 async 函数可能具有一定的意义。此外,如果没有异常或明确取消发生,AsyncRun 应该永远不会完成。

现在的问题是:主程序必须在多个代理上运行它,我想知道运行多个任务的正确方法,在每个完成时发出信号(由于取消/错误): 例如,我正在考虑像这样的无限循环

//.... all task cretaed are in the array tasks..
while(true)
{
     await Task.WhenAny(tasks)
     //.... check each single task for understand which one(s) exited
     // re-run the task if requested replacing in the array tasks
}

但不确定它是否正确(甚至是最佳方式) 此外,我想知道这是否是正确的模式,尤其是因为实现者可能与 RunAsync 不匹配并执行阻塞调用,在这种情况下整个应用程序将挂起。

最佳答案

// re-run the task if requested replacing in the array tasks

这是我考虑更改的第一件事。最好让应用程序处理自己的“重新启动”。如果操作失败,则无法保证应用程序可以恢复。这适用于任何语言/运行时的任何类型的操作。

更好的解决方案是让另一个 应用程序重新启动这个应用程序。允许异常传播(如果可能,记录它),并允许它终止应用程序。然后让你的“经理”进程(字面意思是一个单独的可执行进程)根据需要重新启动。这是所有现代高可用性系统的工作方式,从 Win32 服务管理器到 ASP.NET,再到 Kubernetes 容器管理器,再到 Azure Functions 运行时。

请注意,如果您确实想采用这条路线,将任务拆分到不同的进程可能是有意义的,这样它们就可以独立重新启动。这样一来,一个人的重启不会导致其他人的重启。

但是,如果您想将所有任务都放在同一个进程中,那么您的解决方案就可以了。如果您在流程开始时有已知数量的任务,并且该数量不会改变(除非它们失败),那么您可以通过排除重新启动和使用 Task.WhenAll< 来稍微简化代码 而不是 Task.WhenAny:

async Task RunAsync(Func<CancellationToken, Task> work, CancellationToken token)
{
  while (true)
  {
    try { await work(token); }
    catch
    {
      // log...
    }

    if (we-should-not-restart)
      break;
  }
}

List<Func<CancellationToken, Task>> workToDo = ...;
var tasks = workToDo.Select(work => RunAsync(work, token));
await Task.WhenAll(tasks);
// Only gets here if they all complete/fail and were not restarted.

the implementer can mismatch the RunAsync and do a blocking call, in which case the entire application will hang.

防止这种情况的最佳方法是将调用包装在 Task.Run 中,因此:

await work(token);

变成这样:

await Task.Run(() => work(token));

关于c# - 以安全的方式在企业应用程序中运行多个 Task<>,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56737008/

相关文章:

c# - 我可以从 ASP.net 将大文本值插入到 SQL Server 中,而无需将整个文件保存在 Web 服务器的内存中吗?

c# - OrmLite for ServiceStack 3 不支持可空枚举属性?

java - GWT:使用分离的 mvp 构建小部件

java - 门面模式和管理类

c# - 留在队列中的项目的替代方案(线程消费者生产者)

c# - 非 Controller 类无法访问 DbContext

c# - Winforms Thread Application Hang(后台工作线程)

c++ - 什么是冒名顶替者设计模式?

c# - 为什么 Parallel.For 对这个特定函数的增益如此之小?

c# - 两个并行等待参数