C# 在父级返回时在后台运行异步任务
本文关键字:运行 异步 任务 后台 返回 | 更新日期: 2023-09-27 18:36:59
我正在编写一个 MVC5 应用程序,该应用程序具有一个带有函数的控制器,例如Method1
我有一个第三方函数是 async Task
,我们称之为DoMethodAsync
(它本质上是一个 POST 调用)。
我想在从Method1
回来之前调用它,但我并不真正关心异步任务的结果,如果它失败了,它就会失败。如何触发并忘记并在后台执行它,以便它不会阻止控制器响应其他请求?
如何确保仅在Method1
返回后执行DoMethodAsync
?
我真的不在乎异步任务的结果,如果它失败了,它就失败了。
真?只是问,因为这是一个极其罕见的用例。
如何触发并忘记并在后台执行它,以便它不会阻止控制器响应其他请求?
我有一篇博客文章,研究了在 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
}