【发布时间】:2009-02-06 04:24:51
【问题描述】:
我编写了几个 Java 类 —SingleThreadedCompute 和 MultithreadedCompute — 来证明一个事实(或者我一直认为的事实!),如果您在单核机器,你不会得到加速。事实上,我的理解是,并行化此类任务实际上会减慢速度,因为现在您必须处理上下文切换开销。好吧,我运行了这些类,并且并行版本出乎意料地运行得更快:单线程版本在我的机器上始终以略多于 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 专业版 2002,SP3
- 戴尔精密 670
- 英特尔至强 CPU 2.80GHz,1 MB 二级缓存
不知道如何证明它是单核机器,除了说明上面的规格并指出当我购买机器时(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 毫秒
【问题讨论】:
-
首先,向我们展示 5 次连续运行以及单线程和多线程的运行时间。然后确保我们您确实有一个单核 CPU。
-
我没有windows,也没有单核机,所以不敢尝试,但我赌了一小笔钱,长期运行的任务正在输优先事项;我认为这是一个调度程序问题。
-
@SWMonkey,我说过要关闭 JIT,因为它可能会以不同方式编译两段代码。最好将其从方程式中完全删除。
-
Pax,发布您的“关闭 JIT”答案作为答案(而不是评论),以便我可以接受它...我将发布非 JIT 运行结果...
标签: java multithreading concurrency