Java加速进程/线程
我有一个相当大的数组列表 我必须检查每一个指数,做一个昂贵的计算 我的第一个想法是把它放到一个线程中。 它可以工作,但仍然非常缓慢。我在计算过程中做了一些修改,以降低成本,但计算速度仍然很慢。我想出的最好的解决方案基本上就是这个Java加速进程/线程,java,multithreading,Java,Multithreading,我有一个相当大的数组列表 我必须检查每一个指数,做一个昂贵的计算 我的第一个想法是把它放到一个线程中。 它可以工作,但仍然非常缓慢。我在计算过程中做了一些修改,以降低成本,但计算速度仍然很慢。我想出的最好的解决方案基本上就是这个 public void calculate(){ calculatePart(0); calculatePart(1); } public void calculatePart(int offset) { new Thread() {
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;
}
}
public void run()
{
长a=0;
对于(长i=1;i
在CPU完全完成并退出之前,不会给其他线程控制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));
}
}
}
导入java.util.array;
导入java.util.ArrayList;
导入java.util.List;
导入java.util.concurrent.ExecutionException;
导入java.util.concurrent.ExecutorService;
导入java.util.concurrent.Executors;
导入java.util.concurrent.Future;
公共级加速测试{
公共静态void main(字符串[]args)引发InterruptedException、ExecutionException{
长seqTime、twoThreadTime、多线程时间;
List=Arrays.asList(1,2,3,4,5,6,7,8,9,10);
长时间=System.currentTimeMillis();
顺序处理(列表);
seqTime=System.currentTimeMillis()-时间;
int并行度=2;
ExecutorService ExecutorService=Executors.newFixedThreadPool(并行);
时间=System.currentTimeMillis();
列表任务=新建ArrayList();
对于(int offset=0;offset{
int i=最终偏移量;
while(list.size()>i){
试一试{
processItem(list.get(i));
}捕捉(中断异常e){
e、 printStackTrace();
}
i+=最终平行性;
}
});
任务。添加(任务);
}
用于(未来任务:任务){
task.get();
}
twoThreadTime=System.currentTimeMillis()-时间;
并行度=Runtime.getRuntime().availableProcessors();
executorService=Executors.newFixedThreadPool(并行性);
tasks=newarraylist();
时间=System.currentTimeMillis();
对于(int offset=0;offset{
int i=最终偏移量;
while(list.size()>i){
试一试{
processItem(list.get(i));
}捕捉(中断异常e){
e、 printStackTrace();
}
i+=最终平行性;
}
});
任务。添加(任务);
}
用于(未来任务:任务){
task.get();
}
多线程时间=System.currentTimeMillis()-时间;
日志(“结果:”);
日志(“顺序执行的总时间:“+seqTime/1000.0+”秒”);
日志(“使用2个线程执行的总时间:“+twoThreadTime/1000.0+”秒”);
日志(“使用“+并行+”线程执行的总时间:“+多线程时间/1000.0+”秒”);
}
私有静态无效日志(字符串msg){
System.out.println(msg);
}
私有静态void processItem(int索引)引发InterruptedException{
睡眠(5000);
}
私有静态void sequentialProcessing(列表)抛出InterruptedException{
对于(int i=0;i
输出:
结果:
顺序执行的总时间:50.001秒
使用2个线程执行的总时间:25.102秒
使用4个线程执行的总时间:15.002秒
你到底在做什么样的计算?您是在对列表中的对象进行变异,还是在计算某些对象并将其存储在变量中?这与sp无关