Сколько потоков быстрее заполнит массив?
Дан массив из 10 млн элементов. Хочу понять валидные ли я результаты получил и если нет то где та "золотая середина " между оптимальным количеством потоков и их выполнением. Собственно вот код:
public class MyArray implements Runnable {
private static volatile String[] array;
private final int threadCount;
private final int elemCount;
MyArray(int countOfElements, int countOfThreads) {
array = new String[countOfElements];
threadCount = countOfThreads;
this.elemCount = countOfElements;
}
@Override
public void run() {
try {
long start = System.currentTimeMillis();
for (int i = 0; i < threadCount; i++) {
int part = array.length/threadCount;
for (int index = 0; index < part; index++) {
if (index % 3 == 0 && index % 5 == 0) {
array[index] = "FizzBuzz";
// System.out.println(array[index]);
} else if (index % 5 == 0) {
array[index] = "Buzz";
// System.out.println(array[index]);
} else if (index % 3 == 0) {
array[index] = "Fizz";
// System.out.println(array[index]);
} else {
array[index] = String.valueOf(index);
// System.out.println(array[index]);
}
}
//code for calculating method working time
}
long end = System.currentTimeMillis();
long workTime = end - start;
System.out.println(threadCount + " thread(s) fill of " + array.length + " mln elements array in " + (workTime / 1000.) + " sec");
} catch (Exception exception) {
System.out.println(exception.getMessage());
}
}
}
и потоки в котором заполняются массивы:
public class Main {
public static void main(String[] args) {
Thread thread1 = new Thread(new MyArray(10_000_000, 1));
Thread thread2 = new Thread(new MyArray(10_000_000, 2));
Thread thread3 = new Thread(new MyArray(10_000_000, 5));
Thread thread4 = new Thread(new MyArray(10_000_000, 10));
thread1.start();
thread2.start();
thread3.start();
thread4.start();
}
}
получается вот такое вот время :
5 thread(s) fill of 10000000 mln elements array in 0.84 sec
1 thread(s) fill of 10000000 mln elements array in 0.88 sec
10 thread(s) fill of 10000000 mln elements array in 0.875 sec
2 thread(s) fill of 10000000 mln elements array in 0.897 sec
правильно ли я все сделал и валидные ли результаты?
Ответы (1 шт):
Как сказали в комментах вы создали некорректные условия. Вы в главном треде создаёте 4 треда, которые просто заполняют массив. Вам необходим примерно следующий алгоритм действий:
- Создать в главном треде 4 (если так хотите) треда, по количеству экспериментов.
- В каждом треде в цикле создать ещё ряд тредов,
countOfThreadsединиц. - Каждом треде из предыдущего пункта заполнять массив.
12 в 4 степень возвожу, чтобы имитировать полезную работу.
Конечный код выглядит примерно так:
class MyArray implements Runnable {
private int[][] array;
private final int threadCount;
private final int elemCount;
MyArray(int countOfElements, int countOfThreads) {
array = new int[countOfElements][countOfElements];
threadCount = countOfThreads;
this.elemCount = countOfElements;
}
@Override
public void run() {
Thread[] threads = new Thread[threadCount];
long start = System.currentTimeMillis();
for (int i = 0; i < threadCount; i++) {
threads[i] = new Thread(new Iter(threadCount, i, elemCount, array));
threads[i].start();
}
for (Thread thread : threads) {
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
System.exit(1);
}
}
long end = System.currentTimeMillis();
long workTime = end - start;
for (int[] ints : array) {
for (int anInt : ints) {
if (anInt != (int)Math.pow(12, 4))
throw new RuntimeException();
}
}
System.out.println(threadCount + " thread(s) fill of " + array[0].length * array[0].length / 1_000_000 +
" " +
"mln elements array in " + (workTime / 1000.) + " sec");
}
}
class Iter implements Runnable {
private final int step;
private final int startValue;
private final int elemCount;
volatile private int[][] arrToFill;
public Iter(int step, int startValue, int elemCount, int[][] arrToFill) {
this.step = step;
this.startValue = startValue;
this.elemCount = elemCount;
this.arrToFill = arrToFill;
}
public void run() {
try {
for (int i = startValue; i < elemCount; i += step) {
for (int j = 0; j < elemCount; j++) {
arrToFill[i][j] = (int)Math.pow(12, 4);
}
}
} catch(Exception exception){
System.out.println(exception.getMessage());
}
}
}
public class Main {
public static void main(String[] args) throws InterruptedException {
Thread thread1 = new Thread(new MyArray(20000, 1));
thread1.start();
thread1.join();
Thread thread2 = new Thread(new MyArray(20000, 2));
thread2.start();
thread2.join();
Thread thread3 = new Thread(new MyArray(20000, 5));
thread3.start();
thread3.join();
Thread thread4 = new Thread(new MyArray(20000, 16));
thread4.start();
thread4.join();
}
}
Результат работы такой:
1 thread(s) fill of 400 mln elements array in 7.509 sec
2 thread(s) fill of 400 mln elements array in 3.841 sec
5 thread(s) fill of 400 mln elements array in 1.832 sec
16 thread(s) fill of 400 mln elements array in 1.715 sec
Оптимальным считается количество_ядер х 4 = количество_нитей. Откуда эти числа взяли не спрашивайте, сам не знаю:) Видел в лекциях Головача на YouTube.