我的代码消耗了大量(当前数百万,最终数十亿)相对较短(5-100个元素)的随机数数组,并对它们进行了一些非常费力的数学运算。随机数是,随机的,理想情况下我想在多个核上生成它们,因为随机数生成是> 50%的运行时分析。但是,我很难以一种不比单线程方法慢的方式分发大量小任务。
我的代码目前看起来像这样:
for(int i=0;i<1000000;i++){
for(RealVector d:data){
while(!converged){
double[] shortVec = new double[5];
for(int i=0;i<5;i++) shortVec[i]=rng.nextGaussian();
double[] longerVec = new double[50];
for(int i=0;i<50;i++) longerVec[i]=rng.nextGaussian();
/*Do some relatively fast math*/
}
}
}
我已采取不工作的方法是:
我不是在寻找我的特定问题的“解决方案”,而是如何处理并行生成大型小型独立基元流并从单个线程中消耗它们的一般情况。
答案 0 :(得分:5)
您的性能问题似乎是单个作业太小,因此大部分时间花在执行同步和排队作业本身上。要考虑的一件事是不来生成大量的小作业流,而是向每个工作线程提供一个中等大小的作业集合,它将用答案进行注释。
例如,不是在第一个线程进行迭代#0的情况下迭代你的循环,而是进行迭代#1的下一个线程,...我将让第一个线程进行迭代#0到#999或其他一些。他们应该独立工作并使用他们的计算答案注释Job
类。然后,最后他们可以返回已完成作为Future
的作业的整个集合。
您的Job
课程可能如下所示:
public class Job {
Collection<RealVector> dataCollection;
Collection<SomeAnswer> answerCollection = new ArrayList<SomeAnswer>();
public void run() {
for (RealVector d : dataCollection) {
// do the magic work on the vector
while(!converged){
...
}
// put the associated "answer" in another collection
answerCollection.add(someAnswer);
}
}
}
答案 1 :(得分:4)
这比使用Queue更有效,因为;
double[]
的数组,这意味着后台线程可以在必须将其传递之前生成更多数据。
public class RandomGenerator {
private final ExecutorService generator = Executors.newSingleThreadExecutor(new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r, "generator");
t.setDaemon(true);
return t;
}
});
private final Exchanger<double[][]> exchanger = new Exchanger<>();
private double[][] buffer;
private int nextRow = Integer.MAX_VALUE;
public RandomGenerator(final int rows, final int columns) {
buffer = new double[rows][columns];
generator.submit(new Callable<Void>() {
@Override
public Void call() throws Exception {
Random random = new Random();
double[][] buffer2 = new double[rows][columns];
while (!Thread.interrupted()) {
for (int r = 0; r < rows; r++)
for (int c = 0; c < columns; c++)
buffer2[r][c] = random.nextGaussian();
buffer2 = exchanger.exchange(buffer2);
}
return null;
}
});
}
public double[] nextArray() throws InterruptedException {
if (nextRow >= buffer.length) {
buffer = exchanger.exchange(buffer);
nextRow = 0;
}
return buffer[nextRow++];
}
}
Random是线程安全和同步的。这意味着每个线程都需要它自己的Random来同时执行。
如何处理并行生成大型小型独立基元流并从单个线程中使用它们的一般情况。
我会使用Exchanger<double[][]>
来填充背景中的值,因为它们可以有效地传递它们(没有太多的GC开销)