2014-10-29 2 views
0

저는 프로덕션 코드를 일부 수정했습니다. 예상대로 작동하지 않았습니다. C#으로 작성된 .NET 4.5.1의 Windows 서비스에 대해 이야기하고 있습니다. 그것이 고정되어 있지만, 나는 무슨 일이 일어 났는지 이해하려고 노력하고있다. 어떤 인터넷 검색 결과에 대해서는별로 성과가 없었습니다. 작업은 다음과 같이 시작되었습니다 :Task.Factory.StartNew에는 람다/액션이 필요합니까?

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) 행을 사용하면 제작 과정에서 불이 들지 않지만 람다를 사용하면 매력과 같이 작동합니다.

SimpleInjector를 사용하고 있고 UnitOfWork가 Entity Framework 6.0.2에 의해 지원됩니다. 작업을 시작하는 메서드는 주 스레드의 타이머에 의해 트리거됩니다.

+0

'StartNew' 줄에 더 많은 컨텍스트를 사용할 수 있습니까? 우리는'DoSomeWork'의 시체를 볼 수 있습니까? – Gusdor

+0

예상대로 작동하지 않는다는 것은 무엇을 의미합니까? 이 두 코드 스 니펫은 똑같은 작업을 수행합니다. –

+0

정확히, 나는 두 가지 방법 모두 작동 할 것으로 기대하지만, 처음에는 어떻게 든하지 않았고 이유를 모른다. – Paul

답변

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

감사합니다. 나는 더 많은 것을 조사 할 것이다. 왜냐하면 같은 시간에 여러 개의 tmes를 실행하는 메소드를 막기 위해 Wait()이 필요하기 때문이다. 또한 SimpleInjector를 사용하고 UnitOfWork는 Entity Framework 6.0.2에 의해 지원됩니다. 초기 정보가 부족하다는 것을 변명하십시오. – Paul

+0

또한 작업을 시작하는 메서드가 주 스레드의 Timer 개체에 의해 트리거됩니다. – Paul

+1

'Wait'은 메소드가 동시에 실행되는 것을 막을 것 같지 않습니다. 그것은'lock'이 아니기 때문입니다. 'Timer' 클래스는 무엇을 사용하고 있습니까? 동시 실행 솔루션에서 편집했습니다. – Gusdor