[英]How to process multiple threads at once using Task Parallel Library
我正在使用Asp.Net 4.0。
我还有一个HashSet,我想从中异步创建和运行任务,等待所有任务完成并应用超时。 到目前为止,下面的代码是我目前拥有的代码,但是鉴于使用TPL为猫换皮的方法很多,是否可以对此进行改进,或者是否存在任何关键问题?
TaskWrapper[] taskWrappers = new TaskWrapper[nodeCount];
Task<ResponseWrapper>[] tasks = new Task<ResponseWrapper>[nodeCount];
int i = 0;
foreach (var n in rt.Nodes)
{
tasks[i] = Task<ResponseWrapper>.Factory.StartNew(() => MyMethod.Submit(n.Data, timeout));
taskWrappers[i].LeadPointID = n.LeadPointID;
// other wrapper stuff;
taskWrappers[i].Task = tasks[i];
i++;
}
Task.WaitAll(tasks, timeout);
阅读完好文章后,似乎这种代码结构将是首选的工作方法:
class MyService2
{
public int CalculateMandelbrot()
{
// Tons of work to do in here!
for (int i = 0; i != 10000000; ++i)
;
return 42;
}
}
private async void MyButton_Click(object sender, EventArgs e)
{
await Task.Run(() => myService.CalculateMandelbrot());
}
但是,正如我之前指出的那样,我无法访问VS2012,因此作为起点,是否有一个VS2010等效于此模式?
Task.WaitAll
将阻塞您的主线程,直到所有其他任务完成。 那是一个可以用于处理更多请求的线程。
相反,您应该使用await Task.WhenAll
。 但是, WhenAll
没有需要超时的重载。 可能的解决方法是将其与Task.Delay
,然后等待所有任务完成或延迟任务完成:
await Task.WhenAny(Task.WhenAll(tasks), Task.Delay(timeout));
如果您无权访问VS 2012,则另一种方法是将延续任务附加到WhenAny
,然后返回该任务。 该框架将处理其余的工作。
public Task<string> Post()
{
var tasks = //...
var continuation = Task.WhenAny(Task.WhenAll(tasks), Task.Delay(timeout))
.ContinueWith(whenAnyTask =>
{
//the rest of your code
return "Hello";
};
return continuation;
}
更重要的是:不要在ASP.NET应用程序上使用Task.Run
(或StartNew
)!
您正在从线程池中获取线程以更快地为客户端提供服务,但是这些线程可能被用于服务更多的客户端! 因此,您是在告诉其他客户“请稍等,我正在集中精力先为这个人服务”。 您还将引入很多不必要的开销。
在Web应用程序中,优良作法是一次仅使用一个线程来为客户端提供服务,并仅将异步代码用于异步I / O。
编辑:阿伦
.net(x86)中的每个线程使用1MB RAM或(x64)上4MB。 因此,即使是具有16GB内存的相当强大的服务器也只能运行4000个线程(假设其他地方没有内存使用)。 这意味着,如果每个请求运行4个线程,则您只能同时处理1000个请求。
而node.js服务器(使用与ASP.Net async / await类似的模型)可以轻松地在单个线程上处理10000个并发请求(读取更小的内存占用)。
有关更多详细说明,请参见Stephen Cleary的Task.Run礼节示例:不要在Implementation中使用Task.Run 。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.