很抱歉,我不得不说这个购买你被所有博客误导,声称通过简单地使用Task.Factory.StartNew
是解决你所有问题的方法,好吧,事实并非如此。
使用 Task.Factory.StartNew 进行负载测试
看看我对您的代码进行的以下负载测试(我将睡眠时间更改为 10 秒而不是 1 秒,以使其更糟)。该测试模拟了 200 个固定用户执行总共 2500 个请求。看看有多少由于线程饥饿而失败的请求:
如您所见,即使您将 AsyncController 与 Task 一起使用,线程饥饿仍然会发生。可能是因为长时间运行的过程造成的吗?
使用 TaskCreationOptions.LongRunning 进行负载测试
您知道您可以指定任务是否长时间运行吗?看看这个问题:我不使用 TaskCreationOptions.LongRunning 时的奇怪行为
当您不使用 LongRunning 标志时,任务被安排在线程池线程上,而不是它自己的(专用)线程上。这可能是您的行为改变的原因 -当您在没有设置 LongRunning 标志的情况下运行时,您可能会由于进程中的其他线程而导致线程池不足。
让我们看看如果我们更改 1 行代码会发生什么:
public void ProcessMessageAsync(string id)
{
Task.Factory.StartNew(DoSlowWork, TaskCreationOptions.LongRunning);
AsyncManager.OutstandingOperations.Increment();
}
看看负载测试,有什么不同!
刚刚发生了什么?
如您所见,LongRunning 选项似乎有很大的不同。让我们添加一些日志来看看内部发生了什么:
public void ProcessMessageAsync(string id)
{
Trace.WriteLine(String.Format("Before async call - ThreadID: {0} | IsBackground: {1} | IsThreadPoolThread: {2} | Priority: {3} | ThreadState: {4}", Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsBackground,
Thread.CurrentThread.IsThreadPoolThread, Thread.CurrentThread.Priority, Thread.CurrentThread.ThreadState));
Task.Factory.StartNew(DoSlowWork, TaskCreationOptions.LongRunning);
AsyncManager.OutstandingOperations.Increment();
}
...
private void DoSlowWork()
{
Trace.WriteLine(String.Format("In async call - ThreadID: {0} | IsBackground: {1} | IsThreadPoolThread: {2} | Priority: {3} | ThreadState: {4}", Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsBackground,
Thread.CurrentThread.IsThreadPoolThread, Thread.CurrentThread.Priority, Thread.CurrentThread.ThreadState));
Thread.Sleep(10000);
AsyncManager.OutstandingOperations.Decrement();
}
没有 LongRunning:
Before async call - ThreadID: 11 | IsBackground: True | IsThreadPoolThread: True | Priority: Normal | ThreadState: Background
Async call - ThreadID: 11 | IsBackground: True | IsThreadPoolThread: True | Priority: Normal | ThreadState: Background
使用 LongRunning:
Before async call - ThreadID: 48 | IsBackground: True | IsThreadPoolThread: True | Priority: Normal | ThreadState: Background
Async call - ThreadID: 48 | IsBackground: True | IsThreadPoolThread: False | Priority: Normal | ThreadState: Background
如您所见,如果没有 LongRunning,您实际上是在使用线程池中的线程,从而导致饥饿。虽然 LongRunning 选项在这种情况下效果很好,但您应该始终评估您是否真的需要它。
注意:由于您使用的是 Windows Azure,因此您需要考虑到负载均衡器会在几分钟不活动后超时。