单核系统中Multithreaded与Asynchronous编程的效率差异及实例疑问
问题解答
1. 示例累加程序在单核机器上的运行结果
你提供的是典型的CPU密集型任务,全程没有任何IO等待、锁等待的空耗,CPU全程处于满负载运算状态。放到单核设备上运行时,双线程版本的耗时会高于单线程版本,不会再出现多核下耗时减半的效果:
- 单线程版本耗时和多核下基本一致,没有额外开销
- 双线程版本需要额外支付操作系统的线程调度、上下文切换成本,耗时通常会比单线程慢10%~30%
2. 单处理器环境下多线程与异步编程的效率差异
两者的效率差异仅在IO密集型场景下体现,CPU密集型场景下两者都不可能突破单核算力上限,不会比纯单线程串行执行效率更高:
- 多线程处理IO密集任务时,线程发起IO请求后会被操作系统挂起,IO完成后再唤醒,整个过程存在线程上下文切换开销。如果并发IO任务量很大,大量线程的切换开销会占用大量CPU资源,反而降低整体效率
- 异步编程基于「非阻塞IO+单线程事件循环」实现,发起IO请求后不会挂起线程,会直接继续处理其他待执行任务,等IO完成通知到达后再回头处理后续逻辑,全程没有线程切换开销,单核IO密集场景下的效率远高于多线程方案
3. 单核环境下能否实现同等的效率提升
- 对于你给出的CPU密集型累加任务:不可能实现。这类任务的总运算量固定,单核算力上限固定,没有多余的核心可以用来并行运算,无论用什么编程模型都不可能达到多核双线程的效率
- 对于IO密集型任务:可以实现。异步编程可以把CPU原本等待IO的空闲时间完全利用起来,没有多线程的额外开销,单核下的处理效率甚至可以超过多核多线程方案
附测试代码
class Demonstration { public static void main( String args[] ) throws InterruptedException { SumUpExample.runTest(); } } class SumUpExample { long startRange; long endRange; long counter = 0; static long MAX_NUM = Integer.MAX_VALUE; public SumUpExample(long startRange, long endRange) { this.startRange = startRange; this.endRange = endRange; } public void add() { for (long i = startRange; i <= endRange; i++) { counter += i; } } static public void twoThreads() throws InterruptedException { long start = System.currentTimeMillis(); SumUpExample s1 = new SumUpExample(1, MAX_NUM / 2); SumUpExample s2 = new SumUpExample(1 + (MAX_NUM / 2), MAX_NUM); Thread t1 = new Thread(() -> { s1.add(); }); Thread t2 = new Thread(() -> { s2.add(); }); t1.start(); t2.start(); t1.join(); t2.join(); long finalCount = s1.counter + s2.counter; long end = System.currentTimeMillis(); System.out.println("Two threads final count = " + finalCount + " took " + (end - start)); } static public void oneThread() { long start = System.currentTimeMillis(); SumUpExample s = new SumUpExample(1, MAX_NUM ); s.add(); long end = System.currentTimeMillis(); System.out.println("Single thread final count = " + s.counter + " took " + (end - start)); } public static void runTest() throws InterruptedException { oneThread(); twoThreads(); } }
多核设备运行输出
Single thread final count = 2305843008139952128 took 1003 Two threads final count = 2305843008139952128 took 540
内容的提问来源于stack exchange,提问作者Shikhar
相关产品推荐
相关产品推荐

