Задача, которую я пытаюсь реализовать, - это найти последовательность Коллатца для чисел в заданном интервале, используя несколько потоков, и увидеть, насколько много улучшений по сравнению с одним потоком.
Однако один поток всегда быстрее, независимо от того, выбираю ли я 2 потока (редактировать. 2 потока быстрее, но ненамного, в то время как 4 потока медленнее, чем 1 поток, и я понятия не имею, почему. (Я мог бы даже сказать, что чем больше тем, тем медленнее он становится). Я надеюсь, что кто-то может объяснить. Может быть, я делаю что-то не так.
Ниже мой код, который я написал до сих пор. Я использую ThreadPoolExecutor для выполнения задач (одна задача = одна последовательность Коллатца для одного числа в интервале).
Класс Коллатц:
public class ParallelCollatz implements Runnable {
private long result;
private long inputNum;
public long getResult() {
return result;
}
public void setResult(long result) {
this.result = result;
}
public long getInputNum() {
return inputNum;
}
public void setInputNum(long inputNum) {
this.inputNum = inputNum;
}
public void run() {
//System.out.println("number:" + inputNum);
//System.out.println("Thread:" + Thread.currentThread().getId());
//int j=0;
//if(Thread.currentThread().getId()==11) {
// ++j;
// System.out.println(j);
//}
long result = 1;
//main recursive computation
while (inputNum > 1) {
if (inputNum % 2 == 0) {
inputNum = inputNum / 2;
} else {
inputNum = inputNum * 3 + 1;
}
++result;
}
// try {
//Thread.sleep(10);
//} catch (InterruptedException e) {
// TODO Auto-generated catch block
// e.printStackTrace();
//}
this.result=result;
return;
}
}
И основной класс, в котором я запускаю потоки (да, сейчас я создаю два списка с одинаковыми номерами, так как после запуска с одним потоком начальные значения теряются):
ThreadPoolExecutor executor = (ThreadPoolExecutor)Executors.newFixedThreadPool(1);
ThreadPoolExecutor executor2 = (ThreadPoolExecutor)Executors.newFixedThreadPool(4);
List<ParallelCollatz> tasks = new ArrayList<ParallelCollatz>();
for(int i=1; i<=1000000; i++) {
ParallelCollatz task = new ParallelCollatz();
task.setInputNum((long)(i+1000000));
tasks.add(task);
}
long startTime = System.nanoTime();
for(int i=0; i<1000000; i++) {
executor.execute(tasks.get(i));
}
executor.shutdown();
boolean tempFirst=false;
try {
tempFirst =executor.awaitTermination(5, TimeUnit.HOURS);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
System.out.println("tempFirst " + tempFirst);
long endTime = System.nanoTime();
long durationInNano = endTime - startTime;
long durationInMillis = TimeUnit.NANOSECONDS.toMillis(durationInNano); //Total execution time in nano seconds
System.out.println("laikas " +durationInMillis);
List<ParallelCollatz> tasks2 = new ArrayList<ParallelCollatz>();
for(int i=1; i<=1000000; i++) {
ParallelCollatz task = new ParallelCollatz();
task.setInputNum((long)(i+1000000));
tasks2.add(task);
}
long startTime2 = System.nanoTime();
for(int i=0; i<1000000; i++) {
executor2.execute(tasks2.get(i));
}
executor2.shutdown();
boolean temp =false;
try {
temp=executor2.awaitTermination(5, TimeUnit.HOURS);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("temp "+ temp);
long endTime2 = System.nanoTime();
long durationInNano2 = endTime2 - startTime2;
long durationInMillis2 = TimeUnit.NANOSECONDS.toMillis(durationInNano2); //Total execution time in nano seconds
System.out.println("laikas2 " +durationInMillis2);
Например, работа с одним потоком завершается за 3280 мс. Работает с двумя потоками 3437мс. Должен ли я рассмотреть другую параллельную структуру для расчета каждого элемента?
EDIT
Clarrification. Я не пытаюсь распараллелить отдельные последовательности, но интервал чисел, когда у каждого числа есть своя последовательность (которая не связана с другими числами)
EDIT2
Сегодня я запустил программу на хорошем ПК с 6 ядрами и 12 логическими процессорами, и проблема не устранена. У кого-нибудь есть идея, где может быть проблема? Я также обновил свой код. По некоторым причинам 4 потока делают хуже, чем 2 потока (даже хуже, чем 1 поток). Я также применил то, что было дано в ответе, но без изменений.
Другое Править
Что я заметил, что если я добавлю Thread.sleep (1) в мой метод ParallelCollatz, то производительность будет постепенно увеличиваться с увеличением количества потоков. Возможно, эта деталь говорит кому-то, что не так? Однако независимо от того, сколько задач я выполняю, если нет Thread.Sleep (1) 2 потока выполняют быстрее всего, 1 поток занимает второе место, а другие зависают примерно одинаковое количество миллисекунд, но медленнее, чем потоки 1 и 2.
Новое редактирование
Я также попытался поместить больше задач (для цикла для вычисления не 1, а 10 или 100 последовательностей Коллатца) в метод run () класса Runnable, чтобы сам поток выполнял больше работы. К сожалению, это тоже не помогло.
Возможно я запускаю задачи неправильно? У кого-нибудь есть идеи?
EDIT
Так что может показаться, что после добавления большего количества задач в метод run это немного исправляется, но для большего количества потоков проблема все еще остается 8+. Я все еще задаюсь вопросом, является ли это причиной того, что для создания и запуска потоков требуется больше времени, чем для выполнения задачи? Или я должен создать новый пост с этим вопросом?