C# 在父级返回时在后台运行异步任务

本文关键字:运行 异步 任务 后台 返回 | 更新日期: 2023-09-27 18:36:59

我正在编写一个 MVC5 应用程序,该应用程序具有一个带有函数的控制器,例如Method1

我有一个第三方函数是 async Task ,我们称之为DoMethodAsync(它本质上是一个 POST 调用)。

我想在从Method1回来之前调用它,但我并不真正关心异步任务的结果,如果它失败了,它就会失败。如何触发并忘记并在后台执行它,以便它不会阻止控制器响应其他请求?

如何确保仅在Method1返回后执行DoMethodAsync

C# 在父级返回时在后台运行异步任务

我真的不在乎异步任务的结果,如果它失败了,它就失败了。

真?只是问,因为这是一个极其罕见的用例。

如何触发并忘记并在后台执行它,以便它不会阻止控制器响应其他请求?

我有一篇博客文章,研究了在 ASP.NET 上"即发即弃"任务的各种方法。

不希望只调用该方法并忽略返回的任务,因为该方法将继承发起请求的请求上下文。然后在请求完成后,请求上下文被释放,该方法最终可以放在一个"有趣"的地方 - 有些事情会起作用,但其他事情不会。

因此,最小可行的解决方案是将其包装在Task.Run中:

var _ignored = Task.Run(() => DoMethodAsync());

但是,请注意,ASP.NET 完全不知道此"额外操作"。如果您希望DoMethodAsync有更多机会实际执行完成,则需要使用 HostingEnvironment.QueueBackgroundWorkItem (4.5.2+) 或我自己的BackgroundTaskManager.Run (4.5.0/4.5.1) 将其注册到 ASP.NET 运行时。

还要注意,这些选项都不能保证DoMethodAsync会完成;它们只是给你一个"尽力而为"。对于真正可靠的系统,您需要适当的分布式架构,即具有独立处理器的可靠存储。

我知道这很旧,但是经过几个小时的搜索和自己尝试不同的东西,我遇到了这个线程。将这里的一些信息与其他资源相结合,我能够实现我想要的东西,我相信这与 OP 想要的东西相同。

我想调用一个像/API/Start 这样的 URL,我希望该 URL 立即返回一个视图,上面写着"感谢您开始,稍后再回来查看"。但是,它需要简单地启动后台作业。

这是MVC 5,所以不确定它是否有区别,但是...

旁注:要查看此操作,请使用 2 个 URL 的/默认值/索引 <-- 将报告~5 秒/Default/IndexAsync <-- 将报告~0秒(嗯,你会看到的)

public class DefaultController : Controller
{
    // GET: Sync
    public ActionResult Index()
    {
        System.Diagnostics.Stopwatch myStopwatch = new System.Diagnostics.Stopwatch();
        myStopwatch.Start();
        DoTask();
        myStopwatch.Stop();
        ViewBag.Message = ($"Process took {myStopwatch.Elapsed.TotalSeconds.ToString()}");
        return View("Index");
    }
    // GET: Async
    public ActionResult IndexAsync()
    {
        System.Diagnostics.Stopwatch myStopwatch = new System.Diagnostics.Stopwatch();
        myStopwatch.Start();
        Task.Factory.StartNew(DoTaskAsync);
        myStopwatch.Stop();
        ViewBag.Message = ($"Process took {myStopwatch.Elapsed.TotalSeconds.ToString()}");
        return View("Index");
    }
    // "the Sync Task"
    private void DoTask()
    {
        System.Diagnostics.Debug.Print($"DoTask Started at {DateTime.Now.ToString()}");
        System.Threading.Thread.Sleep(5000);
        System.Diagnostics.Debug.Print($"DoTask Finished at {DateTime.Now.ToString()}");
    }
    // "the Async Task"
    private async Task DoTaskAsync()
    {
        System.Diagnostics.Debug.Print($"DoTaskAsync Started at {DateTime.Now.ToString()}");
        System.Threading.Thread.Sleep(5000);
        System.Diagnostics.Debug.Print($"DoTaskAsync Finished at {DateTime.Now.ToString()}");
    }      
}

调用异步方法意味着调用方法(您的代码)在执行异步方法时不会被阻止,至少默认情况下不会被阻止(您可以通过"await"关键字或通过调用任务的阻止方法之一(如"结果"或"等待"等)使代码块)。
这意味着,如果您只调用该方法,该方法将异步运行,并且您的代码不会等待它结束。我认为这正是你想要的。

public ActionResult Index()
{
    DoMethodAsync(); // if you do not await and simple call this task it will run in backround as you want
    return View();
}
async Task DoMethodAsync()
{
    // calculate something
}