Task.Factory.StartNew在部署时未执行任务

6

我有一些代码,在我的电脑上安装/运行时按预期工作,我的电脑是Windows 7,但在其他服务器(2003和2008)上运行时却不行。这段代码来自一个.NET4 WCF服务库,我在Windows服务中使用它。这里是简化版。

public void monitorQueueAndDoStuff() {
  MonitorRetryQueue();
  MonitorMainQueue();                
}

private void MonitorMainQueue() {
  Log.Info("MonitorMainQueue called");
  Task.Factory.StartNew(() =>
  {
    Log.Info("new thread monitoring queue");
    // ...NMS stuff

        while (!stopped) {
          ITextMessage mess = null;
            mess = blockingMessageCollection.Take();
            sendToQueue(mess);
        }
      }
    }
  });
}


private void MonitorRetryQueue() {
  Task.Factory.StartNew(() =>
  {
    //...NMS stuff
        consumer.Listener += new MessageListener(OnRetryErrorMessage);
        Log.Info("new thread monitoring second queue");

        //need to be constantly up for the consumer to hang around
        while (!stopped) {
          Thread.Sleep(1000);
        }
      }
    }
      });
}

线程应该进入循环执行一些工作。主线程在BlockingCollection上进行阻塞。 现在,它创建了两个任务,但只进入了第二个,它从未在日志中打印“新线程监控队列”。我无法理解为什么不是这样。我尝试了远程调试,但由于它从未进入代码,所以我看不到任何有价值的东西。

我没有发现任何可以改变部署服务器上代码行为的东西。这里有人能够知道原因吗?Visual Studio项目中有任何设置吗?

3个回答

9
有时这种行为表明线程池已经超载。
由于这些任务需要长时间运行/阻塞,它们不应该被安排在线程池中运行,而默认情况下 Task.Factory.StartNew 会将它们发送到线程池中使用的 TaskScheduler 中。
在我看来,Task.Factory.StartNew 可能不太适合这种情况,最好是自己创建线程来运行这些循环。
ThreadStart action=()=>{
    //do your thing
};
Thread thread=new Thread(action){IsBackground=true};
thread.Start();

1
我必须同意,不是因为线程池过载,而是因为任务和线程池适用于那些不会永远运行(任意时间)的事物,而不是像这样需要完成某些有限时间的操作。当您有一些处理循环需要一直运行(直到停止)时,那么专用后台线程是一个很好的选择(就像一些应用程序/框架将具有专用循环以泵送消息一样)。 - James Manning
谢谢,我本来就期望这可能有所帮助,但恐怕使用“ThreadStart”时它的行为是相同的。不过知道“Task.Factory.StartNew”不适合也是好的。 - ejpb
1
好的,我找到了,这与这些方法无关。它需要一个dll,但我没有设置为本地复制。在尝试命令行版本之前,我没有看到任何有关它的消息。我将您的答案设置为正确。 - ejpb
我也遇到了同样的问题,我将任务改为线程,它完美地解决了 :) - Saw
1
我该如何手动或编程地检查线程池是否过载? - Markus

2

日志中是否打印了任何日志信息?您是否看到打印了"MonitorMainQueue called"?您如何知道第二个任务已经启动,但第一个任务没有启动?这可能是创建/写入日志文件的权限问题吗?

编辑:此外,针对@spender关于长时间运行任务的评论,有一种重载方式可以使用该选项启动任务。

Task.Factory.StartNew(MonitorMainQueue, TaskCreationOptions.LongRunning);


这个答案的主要部分应该是对原问题的评论。 - spender
我同意,但是我没有足够的声望点来发表评论。 :) - Paccc
是的,在日志中打印了"MonitorMainQueue called",但之后没有来自该线程的其他内容,只有另一个线程(我从示例中删除了第二个线程的日志语句,现在我已经把它放回去了)。两者都写入同一个日志,所以这不应该有影响。在我的系统上,日志包含了所有三个语句。我尝试使用TaskCreationOptions.LongRunning,但没有任何区别。 - ejpb

1

当我部署到生产环境时,遇到了同样的问题。

问题是由应用程序池使用的标识引起的。

默认情况下,它使用有限权限的applicationPoolIdentity。

我们改为使用"Network Service",然后它就可以工作了。

注:我不是说使用NetWorkService是最好的解决方案,但这显然是一个安全权限问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接