【问题标题】:Async Controllers (MVC), long running process with "stops"异步控制器 (MVC),带有“停止”的长时间运行的进程
【发布时间】:2011-11-05 12:37:36
【问题描述】:

我有兴趣运行一个漫长的过程,我想在结果开始出现后立即更新 UI,而不是等待它完成。

我该怎么办?我读过有关异步控制器的信息,但它们似乎没有为此目的内置任何东西。

在结果进来时将结果保存在 Application/Session 对象中并使用来自客户端的轮询?我可以想到几种可能出错的方法(比如用户关闭页面,并且对象永远留在 Application 对象中 - 需要自己管理这些对象的过期,用于轮询的额外服务器负载等)。

有什么想法吗?

谢谢

【问题讨论】:

    标签: c# asp.net .net asp.net-mvc-3


    【解决方案1】:

    我最近试图解决类似的问题(将长时间运行的服务器操作的实时进度报告回客户端),结果证明SignalR 非常适合这种情况。

    基本上,它是一个包装长轮询和 Web Sockets 的库,使用(透明地)服务器和客户端上可用的任何东西。

    到目前为止,我只有很好的经验。

    【讨论】:

    • 我同意使用打包解决方案比推出自己的解决方案更好。
    • 哇,真是太好了!谢谢!
    【解决方案2】:

    您可以使用 ThreadPool.QueueUserWorkItem 运行长时间运行的任务,它可以更新用户可以轮询的应用程序/会话中的状态。正如你所指出的,这有一些终身问题。除了您指出的之外,应用程序池还可以回收 - 但也许没关系。

    该操作的逻辑范围是什么?是否有人/许多人需要查询进度的系统类型长时间运行的任务?还是代表特定用户的长期任务?如果是后者,那么如果该用户的会话超时等就可以了……如果是前者,那么您需要更持久。例如,您可以将任务请求、状态和进度存储在数据库中。这样,在应用重新启动时,它就可以在它关闭的地方拾取,并且任何人都可以轻松查询(如果是系统级任务,这是一个值得注意的决策点)。

    最后的考虑因素是您是否会拥有多个网络角色(网络场/集群)。如果这比数据库甚至单独的工作角色/服务更合适的话。

    所以这一切都归结为任务的类型、谁需要监控它以及持久性要求是什么。如果它只是一个用户任务,请保持简单,队列用户工作项和会话状态。

    【讨论】:

    • 顺便说一句,在进行轮询时,您可以推断当客户端停止轮询时,他离开了eh页面。这需要一些后台工作人员,但它仍然可行,我曾经这样聊天。
    • 谢谢,这是一个用户启动的任务,它通常需要不到 15 秒,但一两秒后可能会出现初步结果,但做初始轮询让我很困扰 - 如果我想要保持 UI 真正响应 - 如果我只是休眠 ajax 结果直到第一个结果到达,我必须快速且大量地进行轮询 - 这对于我的情况是否被认为是一种好习惯?
    【解决方案3】:

    这篇文章似乎描述了您想要的,简单且没有 SignalR:

    ASP.NET MVC 3: Async jQuery progress indicator for long running tasks

    控制器:

    公共类 HomeController : 控制器 { 私有静态 IDictionary 任务 = new Dictionary();

     public ActionResult Index()
     {
       return View();
     }
    
     public ActionResult Start()
     {
       var taskId = Guid.NewGuid();
       tasks.Add(taskId, 0);
    
       Task.Factory.StartNew(() =>
       {
         for (var i = 0; i <= 100; i++)
         {
           tasks[taskId] = i; // update task progress
           Thread.Sleep(50); // simulate long running operation
         }
         tasks.Remove(taskId);
       });
    
       return Json(taskId);
     }
    
     public ActionResult Progress(Guid id)
     {
       return Json(tasks.Keys.Contains(id) ? tasks[id] : 100);
     }
    

    }

    查看:

    <script type="text/javascript">
    
    function updateMonitor(taskId, status) {
      $("#" + taskId).html("Task [" + taskId + "]: " + status);
    }
    
    $(function () {
      $("#start").click(function (e) {
       e.preventDefault();
       $.post("Home/Start", {}, function (taskId) {
    
         // Init monitors
         $("#monitors").append($("<p id='" + taskId + "'/>"));
         updateMonitor(taskId, "Started");
    
         // Periodically update monitors
         var intervalId = setInterval(function () {
           $.post("Home/Progress", { id: taskId }, function (progress) {
             if (progress >= 100) {
               updateMonitor(taskId, "Completed");
             clearInterval(intervalId);
             } else {
               updateMonitor(taskId, progress + "%");
             }
           });
         }, 100);
       });
     });
    

    });

    【讨论】:

    • 如果您使用的是负载平衡的多个 AppDomain 环境,则效果不佳。
    猜你喜欢
    • 2010-11-12
    • 1970-01-01
    • 2014-02-11
    • 2018-06-03
    • 1970-01-01
    • 2022-01-03
    • 2011-12-25
    • 1970-01-01
    • 2019-02-18
    相关资源
    最近更新 更多