Task.Factory.StartNew requires a lambda / Action?

本文关键字:Action lambda Factory StartNew requires Task | 更新日期: 2023-09-27 18:28:25

我刚刚修复了一些生产代码,但没有按预期工作。我们讨论的是用C#编写的.NET 4.5.1中的Windows服务。虽然它是固定的,但我正在努力了解发生了什么。一些谷歌搜索并没有显示太多结果。任务启动如下:

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

据我所知,就像在Threads中一样,StartNew接收到一个对它应该执行的方法的引用。这在调试环境中是有效的,但在生产(Release)中则不然。以下是:

 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由EntityFramework6.0.2支持。启动任务的方法由主线程上的Timer触发。

Task.Factory.StartNew requires a lambda / Action?

这可能是对Task.Wait的阻塞调用导致死锁的一个示例。

我不熟悉unity,但像this.container.BeginLifetimeScope()container.GetInstance<UnitOfWork>这样的调用可能会调用回入口线程。发布环境可以使用不同的SynchronizationContext进行调试。

如果没有行为的工作示例,很难判断,但请尝试删除对Task.Wait的调用,看看会发生什么!通常认为,在Task完成后使用continuation来安排工作是一种更好的做法。

//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.");