2015-07-11 140 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