使用ArrayList时,Java ExecutorService比serial-in慢



我正试图将一个大列表拆分为两个任务,并进行一些处理,然后将它们合并。在下面的测试中,我发现串行处理比并行处理快得多(或者)我做错了什么。以下是的结果

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,这很令人困惑。

相关内容

  • 没有找到相关文章

最新更新