【问题标题】:Multi-Thread or Async for a lengthy task in a website多线程或异步,用于网站中的冗长任务
【发布时间】:2013-07-22 19:29:55
【问题描述】:

我目前正在运营一个电子商务网站。

所以当用户结账时,我有一个银行回调页面...

但由于我必须在付款发生后执行一项冗长的任务(目前是同步完成的),因此用户必须等待很长时间才能将其重定向回我的网站。

我尝试使用 thread.start 创建一个后台线程,但问题是我失去了会话,这是不明显的。

那么,根据这个描述,您将如何进行?你会选择异步还是多线程?

如果您选择异步,会怎样?

所以我们有类似的东西:

public ActionResult CallBack()
{
    if (AcceptPayment() == "OK")
    {
      LenghtyTask(); 
    }

    return RedirectToUrl("MyWebSite");   
} 

【问题讨论】:

  • 您是要解决用户必须等待很长时间的事实,还是要让这个漫长的过程不再像现在这样对您的整体可扩展性造成太大影响?
  • 您的实际问题是,听起来您希望客户端在运行冗长的任务时使用一些 UI 进行更新,是吗?如果是这样,那么这个问题或多或少毫无意义,因为您需要制作一个ajax请求端点来确定您长时间运行的任务的状态。
  • 异步实际上是在启动一个线程,但是你只是在释放服务器资源,并没有真正让用户的事情变得更快。
  • 我删除了您对 MVP 答案的请求,因为这是一个毫无意义的请求。这里的答案是根据其质量而不是基于某些闪亮的标题而被赞成或否决的。

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


【解决方案1】:

首先,在 ASP.NET 站点中运行后台线程是一个很大的禁忌,因为您无法控制应用程序的生命周期。应用程序池可以关闭或回收,这意味着您会丢失数据。

您可以使用数据库来存储任务(并随着工作的进行更新它们的状态),也可以简单地创建一个 Windows 服务或类似的服务来执行这些工作。


由于您无法控制作业的运行,因此询问您是否应该使用异步或线程是没有意义的,因为它们都不会释放任何资源(即让您的应用程序运行得更快)。

只需选择一个您知道的并让 HTTP 请求完成。告诉用户该作业正在后台处理,并让他刷新浏览器以查看其进展情况。另一种方法是使用 Ajax 或 ASP.NET SignalR 在后台检查进度。

【讨论】:

  • 我同意 100%。如果您希望您的解决方案能够很好地扩展,那么可以考虑使用服务总线或更简单的发布/订阅机制,让另一个进程(可能是 Windows 服务)知道后台有工作要做。
【解决方案2】:

大概会这样

public ActionResult CallBack()
{
    if (AcceptPayment() == "OK")
    {
        // simply launches the task and moves on
        Task.Run(LenghtyTask()); 
    }

    return RedirectToUrl("MyWebSite");   
} 

现在在您的页面上:RedirectToUrl("MyWebSite")

您将不得不像 Tejs 指出的那样设置一个 ajax 请求,当任务完成时可以通知用户

public ActionResult IsTaskFinished()
{
    // No clue where your transaction is, but your gonna need to know it to check it's state
    return JSON(SomeClass.Current.IsTaskFinished(ContextBoundObject.Transaction.Id));
} 

在实际启动 ajax 之前,您可能想在 /MyWebSite 上调用 SomeClass.Current.IsTaskFinished(ContextBoundObject.Transaction.Id) ..以防事务已经完成。

function isTaskFinished() {
    $.post("/IsTaskFinished").always(function(data) {
        if (!!data) {
            setTimout(isTaskFinished, 3000);
        }
        else {
            // yay i'm done, inform user !
        }
    });
}

当然,您必须考虑重试限制、错误处理等。

【讨论】:

  • 任务与后台线程存在相同的问题,因为它们使用线程池。在这里阅读更多:stackoverflow.com/questions/16254567/…
  • 不是说要等待..我同意数据库/队列。但是你必须以一种或另一种方式把它推到那里。 LenghtyTask() 可能是实际任务,也可能只是推送到数据库,具体取决于他想要实现的安全程度。
【解决方案3】:

我会将冗长的操作保留在队列中(MSMQ、RabbitMQ 等),并让工作进程(最好是 Windows 服务器)将作业出列并执行那些冗长的操作。

就您如何通知用户而言,有多种选择,但我的选择是实时更新,您可以通过服务器将其推送到客户端浏览器。只需在您的应用程序上有一个 SignalR 端点,并通过您的工作进程上的 SignalR .NET 客户端连接它。完成冗长的操作后,您可以通过 SignalR 端点通知连接的客户端。

无论您做什么,请避免在 ASP.NET 下进行任何数据关键操作恕我直言的后台操作,正如@jgauffin 指出的那样。原因如下:http://haacked.com/archive/2011/10/16/the-dangers-of-implementing-recurring-background-tasks-in-asp-net.aspx

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-31
    • 1970-01-01
    相关资源
    最近更新 更多