Edu*_*rdo 40 java parallel-processing multithreading
说我有一个类似的任务:
for(Object object: objects) {
Result result = compute(object);
list.add(result);
}
Run Code Online (Sandbox Code Playgroud)
并行化每个compute()的最简单方法是什么(假设它们已经可并行化)?
我不需要一个严格符合上述代码的答案,只需一般答案.但是如果您需要更多信息:我的任务是IO绑定的,这是针对Spring Web应用程序的,任务将在HTTP请求中执行.
ove*_*ink 60
我建议看看ExecutorService.
特别是这样的事情:
ExecutorService EXEC = Executors.newCachedThreadPool();
List<Callable<Result>> tasks = new ArrayList<Callable<Result>>();
for (final Object object: objects) {
Callable<Result> c = new Callable<Result>() {
@Override
public Result call() throws Exception {
return compute(object);
}
};
tasks.add(c);
}
List<Future<Result>> results = EXEC.invokeAll(tasks);
Run Code Online (Sandbox Code Playgroud)
请注意,newCachedThreadPool如果objects是一个大清单,使用可能会很糟糕.缓存的线程池可以为每个任务创建一个线程!你可能想要使用newFixedThreadPool(n)n是合理的东西(比如你拥有的核心数,假设compute()是CPU绑定的).
这是实际运行的完整代码:
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class ExecutorServiceExample {
private static final Random PRNG = new Random();
private static class Result {
private final int wait;
public Result(int code) {
this.wait = code;
}
}
public static Result compute(Object obj) throws InterruptedException {
int wait = PRNG.nextInt(3000);
Thread.sleep(wait);
return new Result(wait);
}
public static void main(String[] args) throws InterruptedException,
ExecutionException {
List<Object> objects = new ArrayList<Object>();
for (int i = 0; i < 100; i++) {
objects.add(new Object());
}
List<Callable<Result>> tasks = new ArrayList<Callable<Result>>();
for (final Object object : objects) {
Callable<Result> c = new Callable<Result>() {
@Override
public Result call() throws Exception {
return compute(object);
}
};
tasks.add(c);
}
ExecutorService exec = Executors.newCachedThreadPool();
// some other exectuors you could try to see the different behaviours
// ExecutorService exec = Executors.newFixedThreadPool(3);
// ExecutorService exec = Executors.newSingleThreadExecutor();
try {
long start = System.currentTimeMillis();
List<Future<Result>> results = exec.invokeAll(tasks);
int sum = 0;
for (Future<Result> fr : results) {
sum += fr.get().wait;
System.out.println(String.format("Task waited %d ms",
fr.get().wait));
}
long elapsed = System.currentTimeMillis() - start;
System.out.println(String.format("Elapsed time: %d ms", elapsed));
System.out.println(String.format("... but compute tasks waited for total of %d ms; speed-up of %.2fx", sum, sum / (elapsed * 1d)));
} finally {
exec.shutdown();
}
}
}
Run Code Online (Sandbox Code Playgroud)
使用 Java8 及更高版本,您可以在集合上使用parallelStream来实现此目的:
List<T> objects = ...;
List<Result> result = objects.parallelStream().map(object -> {
return compute(object);
}).collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)
注意:结果列表的顺序可能与对象列表中的顺序不一致。
在这个 stackoverflow 问题how-many-threads-are-spawned-in-parallelstream-in-java-8中提供了如何设置正确线程数的详细信息
我们可以简单地创建几个线程并获得结果。
Thread t = new Mythread(object);
if (t.done()) {
// get result
// add result
}
Run Code Online (Sandbox Code Playgroud)
编辑:我认为其他解决方案更酷。