繁体   English   中英

Java加速进程/线程

[英]Java speedup processes / threads

我有一个相当大的ArrayList。

我必须经历每个索引,并进行昂贵的计算

我加快速度的第一个想法是把它放到一个线程中。 它有效,但仍然非常慢。 我对计算进行了修改,以降低成本,但仍然会变慢。 我提出的最佳解决方案基本上就是这个。

public void calculate(){
    calculatePart(0);
    calculatePart(1);
}

public void calculatePart(int offset) {
      new Thread() {
            @Override
            public void run() { 
                int i = offset;
                 while(arrayList.size() > i) {
                    //Do the calulation
                     i +=2;
              }
          }              
     }.start();
}

然而,这感觉就像一个懒惰,不专业的解决方案。 这就是为什么我在问是否有更清洁,更快的解决方案

从理论上讲高:如果你有X个元素并且你的计算必须对每个元素执行N次操作,那么你的计算机(处理器)必须执行总共X * N次操作,然后......

只有在计算操作中,当线程在等待时(例如文件或网络操作),并行线程才能使其更快。 其他线程可以使用该时间。 但是如果所有操作都是纯CPU(例如数学)并且线程没有等待 - 执行X * N操作所需的时间保持不变。

此外,每个胎面必须使其他线程能够在某些时候控制CPU。 它会在方法调用之间自动发生,或者如果您在代码中调用了Thread.yield()

作为示例方法,如:

public void run()
{
  long a=0;
  for (long i=1; i < Long.MAX_VALUE; i++)
  {
   a+=i;
  }
 }

在完全完成并退出之前,不会让其他线程有机会控制CPU。

假设对每个元素执行任务不会导致数据争用,您可以利用并行功能。 要最大化同时发生的计算次数,您必须为系统中可用的每个处理器提供任务。

在Java中,您可以使用以下方法获取可用的处理器(核心)数量:

int parallelism = Runtime.getRuntime().availableProcessors();

我们的想法是创建与可用处理器相等的线程数。

因此,如果您有4个处理器可用,则可以创建4个线程并要求它们以4的间隙处理项目。假设您有一个大小为10的列表,需要并行处理。

然后,

线程1处理索引0,4,8处的项目
线程2处理索引1,5,9处的项目
线程3处理索引为2,6的项目
线程4处理索引3,7处的项目

我尝试使用以下代码模拟您的场景:

import java.util.Arrays;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class SpeedUpTest {

    public static void main(String[] args) throws InterruptedException, ExecutionException {
        long seqTime, twoThreadTime, multiThreadTime;
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

        long time = System.currentTimeMillis();
        sequentialProcessing(list);
        seqTime = System.currentTimeMillis() - time;

        int parallelism = 2;
        ExecutorService executorService = Executors.newFixedThreadPool(parallelism);
        time = System.currentTimeMillis();
        List<Future> tasks = new ArrayList<>();
        for (int offset = 0; offset < parallelism; offset++) {

            int finalParallelism = parallelism;
            int finalOffset = offset;
            Future task = executorService.submit(() -> {
                int i = finalOffset;
                while (list.size() > i) {
                    try {
                        processItem(list.get(i));
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    i += finalParallelism;
                }
            });
            tasks.add(task);
        }
        for (Future task : tasks) {
            task.get();
        }
        twoThreadTime = System.currentTimeMillis() - time;

        parallelism = Runtime.getRuntime().availableProcessors();
        executorService = Executors.newFixedThreadPool(parallelism);
        tasks = new ArrayList<>();
        time = System.currentTimeMillis();
        for (int offset = 0; offset < parallelism; offset++) {

            int finalParallelism = parallelism;
            int finalOffset = offset;
            Future task = executorService.submit(() -> {
                int i = finalOffset;
                while (list.size() > i) {
                    try {
                        processItem(list.get(i));
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    i += finalParallelism;
                }
            });
            tasks.add(task);
        }
        for (Future task : tasks) {
            task.get();
        }
        multiThreadTime = System.currentTimeMillis() - time;
        log("RESULTS:");
        log("Total time for sequential execution : " + seqTime / 1000.0 + " seconds");
        log("Total time for execution with 2 threads: " + twoThreadTime / 1000.0 + " seconds");
        log("Total time for execution with " + parallelism + " threads: " + multiThreadTime / 1000.0 + " seconds");


    }

    private static void log(String msg) {
        System.out.println(msg);
    }

    private static void processItem(int index) throws InterruptedException {
        Thread.sleep(5000);
    }

    private static void sequentialProcessing(List<Integer> list) throws InterruptedException {

        for (int i = 0; i < list.size(); i++) {
            processItem(list.get(i));
        }
    }

}

OUTPUT:

结果:

顺序执行的总时间:50.001秒

使用2个线程执行的总时间:25.102秒

4个线程执行的总时间:15.002秒

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM