我有一个需要发出多个Web请求的MVC控制器操作。因此,为了尝试释放此线程来处理其他传入的Web请求,我写了这样的东西: (注意:这是对实际代码的过度简化)
public async Task<ViewResult> Index()
{
MyObj o = await Task.Factory.StartNew<MyObj>(() =>
{
WebClient c = new WebClient();
var res1 = c.DownloadString("...");
var res2 = c.DownloadString("..."); //Not shown but res1 required for this call.
return new MyObj(res1, res2);
}
return View(o);
}
我的问题是,通过启动新线程来完成这项工作,我做得更好或更糟。我的目的是释放这个.Net线程来处理网络请求时的其他传入请求。但看了之后我觉得我还在制作一个.Net线程块,只是可能与线程池不同而不是原始块,所以我真的没有好转。那么我的怀疑是否正确以及上述代码使事情变得更糟?
Task.Factory.StartNew()的好处如果有效......就是它简化了必须完成所有异步的内部工作。我的问题是:这样做是否实际上是一个线程来处理传入的Web请求,还是它仍然从线程池中占用相同数量的线程?
答案 0 :(得分:4)
是的,你现在正在阻止另一个线程。
如果这很好,MVC会自动将所有动作方法包装在新任务中。
要取消阻止线程,您需要在封面下的某个位置使用异步IO。 BCL通常提供这个。如果它说&#34; async&#34;在盒子上它通常是异步IO。
也就是说,很少有网络应用程序存在线程耗尽的问题。如有必要,线程池会启动大量线程。根据可用线程数量,很少有Web应用程序的吞吐量受限。你真的需要处理100个并发请求吗?您的后端服务甚至可以处理此负载吗?如果这些问题中的任何一个被#34; no&#34;你不需要异步。
答案 1 :(得分:2)
您所制作的代码并不是最佳,因为两个长操作都会相互阻塞:
var result1 = c.DownloadString("...");
将首先运行,完成后运行
var result2 = c.DownloadString("...");
在其中运行的额外线程不会提高性能,也不会释放任何打开的请求。
答案 2 :(得分:1)
你不需要工厂。您可以将示例简化为:
public async Task<ViewResult> Index()
{
WebClient client = new WebClient();
var result1 = await client.DownloadStringAsync("...");
var result2 = await client.DownloadStringAsync("...");
/* whatever you're doing with result1 & result2 */
return View();
}