闲置的线程=坏?

时间:2014-03-04 21:04:55

标签: java multithreading asynchronous nio c10k

我想在一小组机器上支持大约10,000个并发HTTP客户端(尽可能小)。我希望在用户使用应用程序时保持与每个客户端的连接,以允许服务器推送更新。

我认为异步IO经常被推荐用于这些类型的长期连接,以避免大量线程处于空闲状态。但线程闲置有什么问题?我发现线程模型在精神上更容易使用,但我不想做一些会让我头疼的事情。我想我将不得不进行实验,但我想知道是否有人知道以前的这些实验中的任何实验?

3 个答案:

答案 0 :(得分:4)

异步I / O基本上意味着您的应用程序执行大部分线程调度。而不是让操作系统随机挂起你的线程并安排另一个线程,你只有与CPU内核一样多的线程,并且在最合适的点上产生其他任务 - 当线程到达I / O操作时,这需要一些时间。

从性能的角度来看,上述似乎是一个明显的胜利,但异步编程模型在几个方面要复杂得多:

  1. 它不能表示为单个函数调用,因此工作流程不明显,尤其是考虑到由于异常而导致的控制流转移时;
  2. 没有特别针对编程语言的支持,成语非常混乱:意大利面条代码和/或极弱的信噪比是常态;
  3. 主要是由于1.上面的调试要困难得多,因为堆栈跟踪并不代表整个工作单元的进度;
  4. 执行从池中的线程跳转到线程(甚至是几个池,每个抽象层都有自己的抽象层),因此使用常用工具进行分析和监视实际上是无用的。
  5. 另一方面,现代操作系统发生了许多有利的改进和优化,这大大消除了同步I / O编程的性能缺点:

    • 地址空间很大,因此为堆栈保留的空间不是问题;
    • 调用堆栈的实际物理RAM负载不是很大,因为只有线程实际使用的堆栈部分被提交到RAM,并且调用堆栈通常不超过64K;
    • 上下文切换,对于更大的线程数而言过去非常昂贵,已经改进到其开销在所有实际目的中可忽略不计的程度。

    经历了上述大部分内容以及其他一些观点的经典论文是我在这里所说的一个很好的补充:

    https://www.usenix.org/legacy/events/hotos03/tech/full_papers/vonbehren/vonbehren_html/index.html

答案 1 :(得分:2)

你的问题的评论中已经有一些很好的指示。

不使用10K线程的原因是这会花费内存资源,而内存会耗费能源。编程模型没有参数,因为坐在客户端连接上的线程不能与想要发布事件的线程相同。

请查看Servlet 3.0标准中的websockets标准和异步请求处理模型。所有最近的Java Web应用程序服务器现在都实现它(例如Glassfish和Tomcat),它是解决您问题的方法。

由于您使用的操作系统,JVM和应用程序服务器缺失,因此无法回答问题本身。但是,您可以通过仅使用Thread.sleep(9999999)创建一个servlet或JSP并在其上执行siege -c 10000 ...来快速测试它。

答案 2 :(得分:1)

  

10,000个并发HTTP客户端......让线程处于空闲状态会有什么问题?

似乎空闲线程的成本只是为内核结构(几kb)和线程堆栈(512kb-mb)分配的内存。但...

显然,你会不时地唤醒你的每一百个线程,对吧?这是您支付上下文切换成本的时刻,这可能不是那么小(调用系统调度程序的时间,更多的缓存未命中等)。例如,见: http://www.cs.rochester.edu/u/cli/research/switch.pdf

您必须非常小心地固定线程,以免影响系统线程。因此,与异步IO相比,每次连接线程(在阻塞IO上)架构可能会增加系统的延迟。但是,如果几乎所有线程都停在大部分时间,它仍然适用于您的情况。

最后一句话。我们不知道你的线程将在read()上被阻塞多少次,以及他们需要做多少工作来处理接收到的数据。将使用哪些硬件,操作系统和网络接口......因此,请测试系统的原型。