Я написал пару классов Java & mdash; SingleThreadedCompute
и MultithreadedCompute
& mdash; чтобы продемонстрировать тот факт (или то, что я всегда считал фактом!), Что если вы распараллелите задачу, ориентированную на вычисления (без ввода-вывода) на одноядерной машине вы не получите ускорение. На самом деле я понимаю, что распараллеливание таких задач на самом деле замедляет ход событий, потому что теперь вам приходится иметь дело с переключением контекста. Ну, я запустил классы, и параллельная версия неожиданно работает быстрее: однопоточная версия постоянно работает на моей машине всего за 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
- Dell Precision 670
- Процессор Intel Xeon 2,80 ГГц, 1 МБ кэш-памяти второго уровня
Не уверен, как доказать, что это одноядерный компьютер, кроме как с указанием спецификации выше и отмечая, что когда я покупал машину (август 2005 г.), одноядерные были стандартом, и я не обновлялся до многоядерных (если это был даже вариант ... я не помню). Если есть что-то в Windows, я могу проверить не «Свойства системы» (где показана информация выше), дайте мне знать, и я проверю.
Вот пять последовательных серий ST и MT:
ПЯТЬ ОДНОСТОРОННИХ РАУНОВ:
общая = 499999999500000000
Истекшее время: 7000 мс
общая = 499999999500000000
Истекшее время: 7031 мс
общая = 499999999500000000
Истекшее время: 6922 мс
общая = 499999999500000000
Истекшее время: 6968 мс
общая = 499999999500000000
Истекшее время: 6938 мс
ПЯТЬ МНОГООБРАЗНЫХ РАБОТ:
общая = 499999999500000000
Истекшее время: 6047 мс
общая = 499999999500000000
Истекшее время: 6141 мс
общая = 499999999500000000
Истекшее время: 6063 мс
общая = 499999999500000000
Истекшее время: 6282 мс
общая = 499999999500000000
Истекшее время: 6125 мс