2012-09-16 36 views
3

所以我有UI在我的应用程序中创建日历事件。当创建新事件时,我为我的所有用户(约3,000)创建通知。我新这将需要一段时间,因为我需要写入数据库为每个用户创建他们的通知,所以我创建了一个继承自BackgroundWorker的类。我并不在意是否创建了通知(我这样做,但不是在为最终用户完成请求的情况下),所以我认为这将是一种有效的方法。BackgroundWorker Still Blocks IHttpHandler

然而当我去执行它时,即使在调用context.Response.End()之后,HttpHandler还是等待后台工作完成。我调试线程和HttpHandlerBackgroundWorker有不同的线程ID。我不确定我是否以某种方式阻止HttpHandler返回,或者我误解了BackgroundWorker类的用途。

class EventHandler : IHttpHandler 
{ 
    ... 
    public void ProcessRequest(HttpContext context) 
    { 
     ... 
     // I need this to finish before the response ends 
     CalendarEvent event = CreateCalendarEvent(); 
     List<int> users = GetUsersFromDB(); 
     if(event != null) // The event was created successfully so create the notifications 
     { 
      // This may take a while and does not effect the UI on 
      // client side, so it can run in the background 
      NotificationBackgroundWorker notificationWorker = new NotificationBackgroundWorker(notification, users); 
      notificationWorker.RunWorkerAsync(); 
     } else { 
      ... 
      // Log Error and set status code for response 
      ... 
     } 
     ... 
     context.Response.End() 
    } 
    ... 
} 

class NotificationBackgroundWorker : BackgroundWorker 
{ 
    private Notification notification; 
    private List<int> users; 

    public NotificationBackgroundWorker(Notification newNotification, List<int> usersToNotify) : base() 
    { 
     this.notification = newNotification; 
     this.users = usersToNotify; 
     this.DoWork += DoNotificationWork; 
    } 

    private void DoNotificationWork(object sender, DoWorkEventArgs args) 
    { 
     CreateUserNotifications(notification, users); 
    } 

    private void CreateUserNotifications(Notification notification, List<int> userList) 
    { 
     // This is where the bottleneck is occurring because there 
     // is one DB write per user 
     foreach (int userId in userList) 
     { 
      ... 
      // Create the notification for each user 
      ... 
     } 
    } 
} 

任何洞察力都会很棒。预先感谢一堆!

+0

鉴于通知积压的可能性以及IIS管理网站线程的方式,我倾向于将通知关闭到Windows服务。 – HABO

+0

就我个人而言,我认为应该只在Windows GUI应用程序(WinForms,WPF)中使用'BackgroundWorker'。 –

+0

所以我认为Uwe是正确的,后台工作人员原本打算在本机应用程序中使用。 – Lull3rSkat3r

回答

5

BackgroundWorker与当前SynchronizationContext整合。它的设计方式是,在BackgroundWorker完成之前,它不会让当前请求结束。这是你大部分时间想要的。

我建议你通过开始新的Task将工作项排入线程池。

+1

因此使用完美的任务。我在下面修改了DoNotificationWork方法以供参考。 '动作作用=(对象物obj)=> {'' CreateUserNotifications(通知,用户);'' };'' 任务的CreateTask = Task.Factory.StartNew(动作 “NotificationCreationTask” + notification.NotificationId) ;' – Lull3rSkat3r

0

在另一个线程中执行而不是使用BackgroundWorker。我不确定BackGroudWorker会在这种情况下工作。

public void ProcessRequest(HttpContext context) 
    { 
     ... 
     // I need this to finish before the response ends 
     CalendarEvent event = CreateCalendarEvent(); 
     List<int> users = GetUsersFromDB(); 
     if(event != null) // The event was created successfully so create the notifications 
     { 

      Thread thread = new Thread(
      () => 
      { 
       CreateUserNotifications(notification, users); 
      }); 
      thread .IsBackground = true; 
      thread.Start(); 

     } else { 
      ... 
      // Log Error and set status code for response 
      ... 
     } 
     ... 
     context.Response.End() 
    }