我观看了这段视频:https://channel9.msdn.com/Events/TechDays/Techdays-2012-the-Netherlands/2287。所以我试图在控制器中实现async / await的使用。所以这基本上就是我所做的:
public class HomeController : Controller
{
private static WebClient _webClient = new WebClient();
public async Task<ActionResult> IndexAsync()
{
var data = await _webClient.DownloadStringTaskAsync("http://stackoverflow.com/");
return View("Index", (object)data);
}
public ActionResult Index()
{
var data = _webClient.DownloadString("http://stackoverflow.com/");
return View("Index", (object)data);
}
}
然后我使用了Apache Benchmark并进行了以下两项测试:
ab -n 100 -c 100 http://localhost:53446/Home/index
和
ab -n 100 -c 100 http://localhost:53446/Home/indexasync
我得到了完全相同的性能(我有8个CPU核心)。那是为什么?
答案 0 :(得分:10)
异步不关于性能。这完全是不正确的。实际上,异步请求通常会同步 less ,只是因为异步涉及额外的开销。
使用异步的原因是有效的资源管理和扩展。典型的Web服务器进程将有大约1000个线程。这通常称为“最大请求”,因为一个线程一般等于一个请求。如果你有一个8核CPU,理想情况下你应该每个核心有一个进程(在IIS中称为“web worker”)。因此,从理论上讲,您总共需要大约8000个线程才能使用。
实际上这是非常多的,尽管现代网页消耗的请求比大多数人想象的要多。页面本身是一个请求,但该页面将包含图像和外部JS和CSS文件,所有这些文件都会生成请求,并且通常会使用AJAX来进一步请求。关键是虽然8000多个线程在你的池中仍然有很多,但如果服务器负载很重,你仍然可以很好地运行。
异步只会让你喘息的空间超过这个极限。在线程进入等待状态的情况下,可以在完成任何外部操作时将其返回到池以记录其他请求。另一种方法是线程只是闲置(同步)。这就是它的全部内容。它完全是关于那些空闲的线程与其他一些工作的任务,这可能意味着排队和超时或被处理的请求之间的差异,即使是缓慢的。
答案 1 :(得分:5)
运行负载测试会耗尽线程池很难在本地方框上进行。通过人为限制线程池来使假装线程池耗尽更容易,就像我in my gist一样:
protected void Application_Start()
{
int workerThreads, ioThreads;
ThreadPool.GetMaxThreads(out workerThreads, out ioThreads);
ThreadPool.SetMaxThreads(Environment.ProcessorCount, ioThreads);
...
}
答案 2 :(得分:3)
有几个原因很突出。
来自Using Asynchronous Methods in ASP.NET MVC 4
线程池中的线程数量有限(.NET 4.5的默认最大值为5,000)。在具有长并行请求的高并发性的大型应用程序中,所有可用线程可能都很忙。这种情况称为线程饥饿。
因此,一次运行100个请求甚至不会开始使你的线程挨饿。
此外,简单的GET请求将非常快速地运行。执行需要几秒甚至几分钟的操作的测试将带来更明显的性能提升。