我编写了几个Java类 - SingleThreadedCompute
并且MultithreadedCompute
- 以证明事实(或者我一直认为是事实!)如果你在一个核心机器上并行化以计算为中心(无I/O)任务,那么你就不会获得加速.事实上,我的理解是并行化这些任务实际上会减慢速度,因为现在你必须处理上下文切换开销.好吧,我运行了类,并行版本出乎意料地运行得更快:单线程版本在我的机器上一直运行超过7秒,并且多线程版本在我的机器上一直运行超过6秒.谁能解释一下这是怎么回事?
如果有人想要查看或尝试自己,这是类.
public final class SingleThreadedCompute { private static final long _1B = 1000000000L; // one billion public static void main(String[] args) { long startMs = System.currentTimeMillis(); long total = 0; for (long i = 0; i < _1B; i++) { total += i; } System.out.println("total=" + total); long elapsedMs = System.currentTimeMillis() - startMs; System.out.println("Elapsed time: " + elapsedMs + " ms"); } }
这是多线程版本:
public final class MultithreadedCompute { private static final long _1B = 1000000000L; // one billion private static final long _100M = _1B / 10L; public static void main(String[] args) { long startMs = System.currentTimeMillis(); System.out.println("Creating workers"); Worker[] workers = new Worker[10]; for (int i = 0; i < 10; i++) { workers[i] = new Worker(i * _100M, (i+1) * _100M); } System.out.println("Starting workers"); for (int i = 0; i < 10; i++) { workers[i].start(); } for (int i = 0; i < 10; i++) { try { workers[i].join(); System.out.println("Joined with thread " + i); } catch (InterruptedException e) { /* can't happen */ } } System.out.println("Summing worker totals"); long total = 0; for (int i = 0; i < 10; i++) { total += workers[i].getTotal(); } System.out.println("total=" + total); long elapsedMs = System.currentTimeMillis() - startMs; System.out.println("Elapsed time: " + elapsedMs + " ms"); } private static class Worker extends Thread { private long start, end; private long total; public Worker(long start, long end) { this.start = start; this.end = end; } public void run() { System.out.println("Computing sum " + start + " + ... + (" + end + " - 1)"); for (long i = start; i < end; i++) { total += i; } } public long getTotal() { return total; } } }
以下是运行单线程版本的输出:
total=499999999500000000 Elapsed time: 7031 ms
这是运行多线程版本的输出:
Creating workers Starting workers Computing sum 0 + ... + (100000000 - 1) Computing sum 100000000 + ... + (200000000 - 1) Computing sum 200000000 + ... + (300000000 - 1) Computing sum 300000000 + ... + (400000000 - 1) Computing sum 400000000 + ... + (500000000 - 1) Computing sum 500000000 + ... + (600000000 - 1) Computing sum 600000000 + ... + (700000000 - 1) Computing sum 700000000 + ... + (800000000 - 1) Computing sum 800000000 + ... + (900000000 - 1) Computing sum 900000000 + ... + (1000000000 - 1) Joined with thread 0 Joined with thread 1 Joined with thread 2 Joined with thread 3 Joined with thread 4 Joined with thread 5 Joined with thread 6 Joined with thread 7 Joined with thread 8 Joined with thread 9 Summing worker totals total=499999999500000000 Elapsed time: 6172 ms
编辑:有关环境的信息:
Microsoft Windows XP Professional版本2002,SP3
戴尔Precision 670
Intel Xeon CPU 2.80GHz,1 MB L2缓存
不知道如何证明它是单核心机器,而不是通过陈述上述规格,并在我购买机器时注意到这一点(2005年8月),单核是标准的,我没有升级到多核(如果这是甚至一个选项...我不记得了).如果Windows中的某个地方我可以检查除系统属性(显示上面的信息)以外的其他信息,请告诉我,我会检查.
这是连续五次ST和MT运行:
五个单人游戏:
总计= 499999999500000000经过时间:7000毫秒
总计= 499999999500000000经过时间:7031毫秒
总计= 499999999500000000经过时间:6922毫秒
总计= 499999999500000000经过时间:6968毫秒
总计= 499999999500000000经过时间:6938毫秒
五个多线程运行:
总计= 499999999500000000经过时间:6047毫秒
总计= 499999999500000000经过时间:6141毫秒
总计= 499999999500000000经过时间:6063毫秒
总计= 499999999500000000经过时间:6282毫秒
总计= 499999999500000000经过时间:6125毫秒
这可能是由于超线程和/或流水线操作造成的.
来自维基百科的超线程:
超线程是超线程的进步.超线程(官方称为超线程技术或HTT)是一种英特尔专有技术,用于改进在PC微处理器上执行的计算并行化(一次执行多个任务).启用了超线程的处理器被操作系统视为两个处理器而不是一个处理器.这意味着只有一个处理器在物理上存在,但操作系统看到两个虚拟处理器,并在它们之间共享工作负载.
来自维基百科的piplining:
在计算中,管道是一组串联连接的数据处理元件,因此一个元件的输出是下一个元件的输入.管道的元素通常以并行或时间切片的方式执行