Ich versuche, eine große Liste in zwei Aufgaben zu teilen und einige Verarbeitung durchzuführen und später zusammenzuführen. Im folgenden Test fand ich heraus, serielle Verarbeitung ist viel schneller als parallel (oder) mache ich etwas falsch. ist unter dem Ergebnis,Java ExecutorService langsamer als seriell bei Verwendung von ArrayList ist es?
sh-4.3$ java -Xmx128M -Xms16M FutureTaskDemo
I =2
Sequential Result : 2000000 calculated in 2339 ms
First Value:2 List Value:2000001
Initial List First Value:2 List Value:2000001
I =1000004
I =4
1000000
1000000
Merging
Parallel Result : 2000000 calculated in 3207 ms
First Value:4 List Value:2000003
Unten ist der Code,
import java.util.ArrayList;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
public class FutureTaskDemo {
/**
* Maximum amount of numbers to check
*/
public static final int MAX_NUMBER = 2_000_000;
public static List<Integer> addOneToListS(List<Integer> list) {
Integer flag=0;
for(Integer i = 0;i<list.size();i++)
{
if(flag==0) System.out.println("I ="+(list.get(i)+2));
list.set(i, list.get(i) +2);
flag=1;
}
return list;
}
public static List<Integer> addOneToListP(List<Integer> list)
throws InterruptedException, ExecutionException {
List<Integer> listA = new ArrayList<>(list.subList(0,MAX_NUMBER/2));
List<Integer> listB = new ArrayList<>(list.subList(MAX_NUMBER/2,MAX_NUMBER));
// Prepare to execute and store the Futures
int threadNum = 2;
ExecutorService executor = Executors.newFixedThreadPool(threadNum);
List<FutureTask<List<Integer>>> taskList = new ArrayList<FutureTask<List<Integer>>>();
// Start thread for the first half of the numbers
FutureTask<List<Integer>> futureTask_1 = new FutureTask<List<Integer>>(new Callable<List<Integer>>() {
@Override
public List<Integer> call() {
return FutureTaskDemo.addOneToListS(listA);
}
});
taskList.add(futureTask_1);
executor.execute(futureTask_1);
// Start thread for the second half of the numbers
FutureTask<List<Integer>> futureTask_2 = new FutureTask<List<Integer>>(new Callable<List<Integer>>() {
@Override
public List<Integer> call() {
return FutureTaskDemo.addOneToListS(listB);
}
});
taskList.add(futureTask_2);
executor.execute(futureTask_2);
// Wait until all results are available and combine them at the same time
Integer totalsize = 0;
for (int j = 0; j < threadNum; j++) {
FutureTask<List<Integer>> futureTask = taskList.get(j);
System.out.println(futureTask.get().size());
}
executor.shutdown();
System.out.println("Merging");
List<Integer> fullList = new ArrayList<>();
fullList.addAll(futureTask_1.get());
fullList.addAll(futureTask_2.get());
return fullList;
}
public static void main(String[] args) throws InterruptedException, ExecutionException {
// Sequential execution
List<Integer> initialList = new ArrayList<>();
for(int i=0;i<MAX_NUMBER;i++)
initialList.add(i);
long timeStart = Calendar.getInstance().getTimeInMillis();
List<Integer> addedList1 = FutureTaskDemo.addOneToListS(initialList);
long timeEnd = Calendar.getInstance().getTimeInMillis();
long timeNeeded = timeEnd - timeStart;
System.out.println("Sequential Result : " + addedList1.size()+ " calculated in " + timeNeeded + " ms");
System.out.println("First Value:"+addedList1.get(0)+" List Value:"+addedList1.get(addedList1.size()-1));
System.out.println("Initial List First Value:"+initialList.get(0)+" List Value:"+initialList.get(initialList.size()-1));
timeStart = Calendar.getInstance().getTimeInMillis();
List<Integer> addedList2 = FutureTaskDemo.addOneToListP(initialList);
timeEnd = Calendar.getInstance().getTimeInMillis();
timeNeeded = timeEnd - timeStart;
System.out.println("Parallel Result : " + addedList2.size()+ " calculated in " + timeNeeded + " ms");
System.out.println("First Value:"+addedList2.get(0)+" List Value:"+addedList2.get(addedList2.size()-1));
}
}
Vielen Dank Peter für die Beantwortung. In dem obigen Programm ist das Hinzufügen von 2 die einzige Verarbeitung, die ich gerade mache. Versucht mit parallelen Streams, die Ergebnisse waren ähnlich. Primitive Ganzzahl-Arrays arbeiten sehr schnell. Da dies eine Übung iam tut, um zu sehen, ob Parallelität besser ist, wenn ich die MAX_NUMBERS auf 10 Millionen änderte, zeigen Ergebnisse noch serielle Verarbeitung ist besser. Mein ursprüngliches Problem ist, ich habe rund 50k interne HTML-Links in einer Liste und zu scannen und zu finden & Keywords verwendet oder nicht. Die serielle Verarbeitung ist sehr langsam. Also dachte ich daran, Liste 32 zu teilen, da 32 Kerne verfügbar waren. –
@ bobby.dreamer die Kosten der Verschiebung von Daten zwischen Threads ist nicht trivial. Im HTML-Link-Beispiel sind die Kosten für die Weitergabe der URL im Vergleich zu den Kosten der HTTP-Anfrage trivial, sodass Sie eine gute Geschwindigkeit sehen sollten. Stellen Sie sich vor, Sie würden viel Zeit darauf verwenden, auf die Anfragen zu warten. Sie könnten feststellen, dass 32 Kerne 64 Threads verarbeiten können, vor allem Hyper-Threading und vielleicht sogar 100 oder 200 Threads, je nachdem, wie lange sie warten. –