我正试图将一个大列表拆分为两个任务,并进行一些处理,然后将它们合并。在下面的测试中,我发现串行处理比并行处理快得多(或者)我做错了什么。以下是的结果
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
下面是代码,
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));
}
}
我会使用并行流
public static List<Integer> addOneToListP(List<Integer> list) {
return list.parallelStream().map(i -> i + 1).collect(Collectors.toList());
}
这要短得多,更简单,更容易理解。它是否更快,将取决于你所做的是通过拥有更多的CPU来加速,还是使用多个线程并在它们之间传递数据的开销太高。您的并行版本正在对数据进行大量复制。
你最大的开销可能是你正在创建的垃圾率非常高。我想看看一个没有那么多垃圾的集合会发生什么。
public static int[] addOneToListP(int[] array) {
return IntStream.of(array).parallel().map(i -> i + 1).toArray();
}
无论有没有多个CPU,这都应该使用一小部分内存,并且速度要快得多。
注意:您的addOneToListS
似乎添加了2
,这很令人困惑。