[英]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.