我刚刚修改了一些生产代码,但没有按预期工作。我们正在讨论用.NET编写的.NET 4.5.1中的Windows服务。虽然它已经修好了,但我试图了解发生了什么。一些谷歌搜索没有显示出太多的结果。正在开展的任务如下:
var task = Task.Factory.StartNew(this.SendReminders);
logger.Info("Waiting for sending to complete...");
task.Wait();
据我所知,在Threads中,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 :(得分: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.");