保证代码在单独的线程中完成

时间:2017-03-14 08:38:41

标签: c# asp.net .net multithreading task-parallel-library

我编写了以下代码来在不同的线程中执行一个方法来将新工作卸载到新线程,以便我的主线程可以快速处理剩余的工作并完成网页请求。

public static Task ExecuteAsynchronously(Action action)
{
    HttpContext currentContext = HttpContext.Current;
    System.Threading.Tasks.Task task = System.Threading.Tasks.Task.Factory.StartNew(()
        =>
    {
        HttpContext.Current = currentContext;
        // Execute the desired action
        action();
    });
    return task;
}

我将从页面的页面加载事件中的ASP.NET Web UI上下文中调用该方法:

protected void Page_Load(object sender, EventArgs e)
{
    MethodA()

    Utility.ExecuteAsynchronously(() =>
    {
        // Do a long running task in separate thread
        MethodC()
    });

    MethodB()
}

我对上述代码有以下问题:

  1. 是否保证代码"在单独的线程中执行长时间运行的任务"将完成或如果页面加载事件它可以中止 在MethodAMethodB方法完成工作之前完成?

  2. 我们甚至可以在Task.Factory.StartNew上下文中使用ASP.NET吗? 保证我们在单独任务中分配的工作能否完成?

  3. 我们怎样才能确保承担重/长的操作负荷(在某些情况下) 远离ASP.NET主要服务于的线程 请求并确定单独线程中的代码将完成 并且在ASP.NET页面的请求之间不会中止 完成之前?这甚至可能吗?

  4. 我们可以使用async-await来解决这个问题吗?

  5. 编辑:请注意我不是在谈论可以定期运行的后台任务。

2 个答案:

答案 0 :(得分:1)

  

是否可以保证代码Do a long running task in separate thread完成,或者如果页面加载事件在MethodAMethodB方法完成工作之前完成,它可以中止?

不,它根本没有保证。此外,此任务'线程可能会重复用于处理其他一些响应,而不会通知您。

  

我们甚至可以在ASP.NET上下文中使用Task.Factory.StartNew并确保我们在单独任务中分配的工作能够完成吗?

正如已经说过的,这些都不是保证。此外,StartNew是不应使用的内部方法,Task.Run更可取,但在这种情况下无用。

  

我们怎样才能确保将重/长操作负载(在某种方法中)远离ASP.NET主要提供请求的线程,并且确定单独线程中的代码将完成并且不会中断什么时候ASP.NET页面的请求完成?这甚至可能吗?

正如评论中已经说过的那样,如果您不需要后台任务的结果,那么应该使用HostingEnvironment.QueueBackgroundWorkItem方法进行此类工作。

  

我们可以使用async-wait来解决这个问题吗?

根据定义,

ASP.NET已经是异步。如果需要结果,则无需另一个线程来执行操作 - 只需在当前线程中运行代码。

现在,回到真实问题。您要做的是将HttpContext.Current传递给后台任务,这是不建议做的事情。来自MSDN

  

来电者的ExecutionContext未流入工作项。例如,您在后台线程中运行的代码无权访问常用的上下文属性。 如果您需要HttpContext信息,请将您关注的值复制到州对象或封闭内,并将其传递给后台工作人员。

     

不要传递HttpContext实例本身,,因为它不是线程安全的对象,甚至可能会抛出简单的属性获取器(如HttpContext.Request.Url)。

因此,您需要将代码更改为HostingEnvironment.QueueBackgroundWorkItem usage并从HttpContext复制值。

其他相关资源:

答案 1 :(得分:-1)

  

假设操作的完成与请求无关,并且它与它无关,但是我希望即使请求已经关闭/完成也要完成该任务。如果我们省略await关键字来调用ExecuteAsynchronously

,那么该任务是否会完成

在这种情况下,不能保证完成。我认为最好的方法是在一个单独的过程中运行该任务。你可以在Windows服务或其他任何东西托管它。这样,所有请求都会通知服务需要运行任务。这样就可以确保任务完成并将问题与请求分开。