#java #multithreading #concurrency
#java #многопоточность #параллелизм
Вопрос:
В следующей программе я хочу отсортировать 4 разных массива параллельно, поэтому использовал ExecutorService для создания FixedThreadPool размером 4 (количество доступных процессоров). Я предполагаю, что это займет меньше времени по сравнению с последовательной операцией, но я вижу, что последовательная операция выполняется быстрее. Здесь нужна какая-либо дальнейшая оптимизация?
Вот код:
public class ThreadFoolOptimumSize {
private static int data1[] = new int[10000];
private static int data2[] = new int[20000];
private static int data3[] = new int[10000];
private static int data4[] = new int[30000];
public static void main(String ars[]) {
long startTime = System.currentTimeMillis();
int processors_count = Runtime.getRuntime().availableProcessors();
System.out.println(processors_count);
Random random = new Random();
data1 = random.ints(10000, 10, 10000).toArray();
data2 = random.ints(20000, 10, 20000).toArray();
data3 = random.ints(10000, 10, 10000).toArray();
data4 = random.ints(30000, 10, 30000).toArray();
ExecutorService executorService = Executors.newFixedThreadPool(processors_count);
executorService.execute(new Runnable() {
public void run() {
Arrays.sort(data1);
System.out.println("sorted data1:");
System.out.println(Arrays.toString(data1));
}
});
executorService.execute(new Runnable() {
public void run() {
Arrays.sort(data2);
System.out.println("sorted data2:");
System.out.println(Arrays.toString(data2));
}
});
executorService.execute(new Runnable() {
public void run() {
Arrays.sort(data3);
System.out.println("sorted data3:");
System.out.println(Arrays.toString(data3));
}
});
executorService.execute(new Runnable() {
public void run() {
Arrays.sort(data4);
System.out.println("sorted data4:");
System.out.println(Arrays.toString(data4));
}
});
executorService.shutdown();
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
long endTime = System.currentTimeMillis();
System.out.println("Total:" (endTime-startTime) " ms");
}
});
}
}
Комментарии:
1. Вы создаете
processors_count
потоки, но для запуска основного потока требуется ядро процессора. И для запуска операционной системы требуется хотя бы одно ядро. Кроме того, мне было бы интересно, использует ли ваша последовательная версия перехват завершения работы для вычисления прошедшего времени.
Ответ №1:
Я повторил ваш тест и подтверждаю ваше наблюдение: я просто думаю, что настройка службы Executor требует затрат, я провел несколько дополнительных тестов на ноутбуке с 8 ядрами, и даже увеличив все массивы в десять раз, я все равно получаю стандартную версию быстрее.
Увеличение еще в десять раз (таким образом, размеры порядка миллионов) Я, наконец, заставляю исполнителя работать быстрее.
Таким образом, очевидно, что вопрос о том, сколько данных вам нужно обработать, в некоторых случаях не стоит использовать исполнителя. (Конечно, я прокомментировал распечатку отсортированных массивов).
Кроме того, добавьте, что использование разных размеров массивов делает разницу менее заметной: вначале вы сортируете 4 массива параллельно, через 1/3 времени вы выполняете 2 сортировки, data1 и data3, и продолжаете обрабатывать параллельно два других, data2 и data4, и последнюю треть времени вы обрабатываете один массив, data4. Если вы отсортируете идентичные массивы, выигрыш в скорости будет более очевидным.
Наконец, позвольте мне добавить, что измеренное время сильно колеблется, вам нужно повторить его несколько раз и усреднить, чтобы получить стабильное число и выполнить надлежащий тест. При размерах в несколько 100 000 с время колеблется на целых 50% на моем ноутбуке.