2014-10-29 111 views
0

我只是修复了一些生产代码,那是不能按预期工作。我们正在讨论用C#编写的.NET 4.5.1中的Windows服务。虽然它是固定的,但我试图理解发生了什么。一些谷歌搜索没有在这方面显示太多的结果。一个任务开始如下:Task.Factory.StartNew需要lambda/Action?

var task = Task.Factory.StartNew(this.SendReminders); 
logger.Info("Waiting for sending to complete..."); 
task.Wait(); 

据我所知,在线程中,StartNew接收到它应该执行的方法的引用。那么这在调试环境中工作,但它不在生产(发布)。以下是:

var task = Task.Factory.StartNew(() => this.SendReminders()); 
logger.Info("Waiting for sending to complete..."); 
task.Wait(); 

我在这里错过了什么?代码是否以一种完全不被执行的方式进行了优化?

按照要求,任务方法的主体:

internal void SendReminders() 
    { 
     using (this.container.BeginLifetimeScope()) 
     { 
      try 
      { 
       var uow = container.GetInstance<UnitOfWork>(); 

       this.logger.Info("Sending reminders.."); 

       var handler = container.GetInstance<IHandleCommand<SendReminderCommand>>(); 
       handler.Handle(new SendReminderCommand()); 
       uow.SaveChanges(); 

      } 
      catch (Exception ex) 
      { 
       this.logger.Exception(ex); 

       throw; 
      } 
     } 
    } 

到目前为止,没有例外已经被记录和服务正在运行。使用Task.Factory.StartNew(this.SendReminders)这一行在生产中没有触发,但使用lambda就像一个魅力。

我正在使用SimpleInjector,UnitOfWork由Entity Framework 6.0.2支持。启动任务的方法由主线程上的Timer触发。

+0

你可以给'StartNew'使用更多的上下文吗?我们是否也可以看到“DoSomeWork”的主体? – Gusdor 2014-10-29 09:01:35

+0

你的意思是不按预期工作?这两个代码片段做同样的事情。 – 2014-10-29 09:10:05

+0

准确地说,我也希望这两种方法都能正常工作,但第一种方法没有办法,我不知道为什么。 – Paul 2014-10-29 09:14:40

回答

2

这可能是阻塞呼叫Task.Wait导致死锁的一个示例。

我不熟悉统一,但调用如this.container.BeginLifetimeScope()container.GetInstance<UnitOfWork>可能会调用回到入口线程。发布环境可能正在使用不同的SynchronizationContext进行调试。

如果没有行为举例,很难说清楚,但请尝试删除对Task.Wait的呼叫,看看会发生什么!在Task完成后,使用延续来安排工作是一种更好的做法。

//m_RemindersTask is a member of type Task 
if(m_RemindersTask != null && m_RemindersTask.Status != TaskStatus.Running) //prevent simultaneous execution 
{ 
    m_RemindersTask = Task.Factory.StartNew(() => this.SendReminders()); 
    logger.Info("Waiting for sending to complete..."); 
    task.ContiueWith(p => /*work to be done after the task*/, 
    TaskScheduler.FromCurrentSynchronizationContext()); //this [optional parameter] makes sure that the continuation is run on the same thread that the scheduling method is run on, if possible. 
} 
else 
    //Is Warning the correct method? You get the idea 
    logger.Warning("Cannot send reminders: reminders are already being sent."); 
+0

感谢您对此的见解。我将进一步调查这一点,因为我需要Wait()来防止同时运行多个tmes的方法。另外,我使用SimpleInjector,UnitOfWork由Entity Framework 6.0.2支持。请原谅我缺乏初始信息。 – Paul 2014-10-29 09:35:55

+0

此外,启动任务的方法正在由主线程上的Timer对象触发。 – Paul 2014-10-29 09:37:42

+1

“等待”不可能阻止该方法同时执行 - 它不是“锁定”。你正在使用什么'Timer'类?我编辑了一个同时运行的解决方案 – Gusdor 2014-10-29 09:46:26