2015-07-11 115 views
2

我有一个ASP.Net应用程序,其中后台任务运行使用HostingEnvironment.QueueBackgroundWorkItem如下面的代码。HostingEnvironment.QueueBackgroundWorkItem使用ASP.Net线程池或另一个线程池?

问题:后台任务是否会在下面的代码中调度,使用ASP.Net线程池线程中的线程,还是使用来自单独线程池的线程?

public ActionResult SendCustMails() 
{ 
     HostingEnvironment.QueueBackgroundWorkItem(ct => SendCustMailsTo(ct, "Customer Notification")); 
     return View(); 
} 

private void SendCustMailsTo (CancellationToken ct, string msg) 
{ 
     //some code is omitted 
     foreach (var customer in Customers) 
     { 
      if (ct.IsCancellationRequested) 
      { 
        break; 
      } 

      SendMail(customer, msg); 
     } 

     return ct; 
} 

回答

2

正如从Hosting environment source code QueueBackgroundWorkItem方法可以看出使用_backGroundWorkScheduler场是BackgroundWorkScheduler的类型来安排后台工作项目:

public sealed class HostingEnvironment : MarshalByRefObject { 
//other field declarations 
private static HostingEnvironment _theHostingEnvironment; 
private BackgroundWorkScheduler _backgroundWorkScheduler = null; // created on demand 
//yet more field declarations 


//methods 
[SecurityPermission(SecurityAction.LinkDemand, Unrestricted = true)] 
    public static void QueueBackgroundWorkItem(Action<CancellationToken> workItem) { 
     if (workItem == null) { 
      throw new ArgumentNullException("workItem"); 
     } 

     QueueBackgroundWorkItem(ct => { workItem(ct); return _completedTask; }); 
    } 

    // See documentation on the other overload for a general API overview. 
    // 
    // This overload of QueueBackgroundWorkItem takes a Task-returning callback; the 
    // work item will be considered finished when the returned Task transitions to a 
    // terminal state. 
    [SecurityPermission(SecurityAction.LinkDemand, Unrestricted = true)] 
    public static void QueueBackgroundWorkItem(Func<CancellationToken, Task> workItem) { 
     if (workItem == null) { 
      throw new ArgumentNullException("workItem"); 
     } 
     if (_theHostingEnvironment == null) { 
      throw new InvalidOperationException(); // can only be called within an ASP.NET AppDomain 
     } 

     _theHostingEnvironment.QueueBackgroundWorkItemInternal(workItem); 
    } 

    private void QueueBackgroundWorkItemInternal(Func<CancellationToken, Task> workItem) { 
     Debug.Assert(workItem != null); 

     BackgroundWorkScheduler scheduler = Volatile.Read(ref _backgroundWorkScheduler); 

     // If the scheduler doesn't exist, lazily create it, but only allow one instance to ever be published to the backing field 
     if (scheduler == null) { 
      BackgroundWorkScheduler newlyCreatedScheduler = new BackgroundWorkScheduler(UnregisterObject, Misc.WriteUnhandledExceptionToEventLog); 
      scheduler = Interlocked.CompareExchange(ref _backgroundWorkScheduler, newlyCreatedScheduler, null) ?? newlyCreatedScheduler; 
      if (scheduler == newlyCreatedScheduler) { 
       RegisterObject(scheduler); // Only call RegisterObject if we just created the "winning" one 
      } 
     } 

     scheduler.ScheduleWorkItem(workItem); 
    } 
//yet more methods 

}

如果我们放眼BackgroundWorkScheduler类的源代码:

internal sealed class BackgroundWorkScheduler : IRegisteredObject { 
//.... 
public void ScheduleWorkItem(Func<CancellationToken, Task> workItem) { 
     Debug.Assert(workItem != null); 

     if (_cancellationTokenHelper.IsCancellationRequested) { 
      return; // we're not going to run this work item 
     } 

     // Unsafe* since we want to get rid of Principal and other constructs specific to the current ExecutionContext 
     ThreadPool.UnsafeQueueUserWorkItem(state => { 
      lock (this) { 
       if (_cancellationTokenHelper.IsCancellationRequested) { 
        return; // we're not going to run this work item 
       } 
       else { 
        _numExecutingWorkItems++; 
       } 
      } 

      RunWorkItemImpl((Func<CancellationToken, Task>)state); 
     }, workItem); 
    } 
//other methods 
} 

我们可以注意到它在内部使用Asp.Net ThreadPool来安排工作项目。

+0

感谢您的详细解答。我猜HangFire是最好的选择,如果你想使用一个单独的线程池,而不是使用ASP.Net线程池。我不喜欢使用ASP.Net池中的线程进行后台任务的想法。 – Sunil

+0

@Sunil不客气。我也很有兴趣知道。 – Umriyaev