简而言之:我正在尝试使用 ExecutorService 来运行多个线程,并且多线程的计算时间比单线程的计算时间要差得多,所以我试图找出我哪里出错了。如果细节不重要,请跳过下面的冗长部分以获取代码。
长篇大论:我设置了一个蒙特卡罗方法来计算半径为 1 的圆的面积来近似 PI 的值。我将其建模为使用随机的 x 和 y 坐标模拟在圆圈上投掷飞镖。经过大量的投掷,圆的面积可以近似为有多少飞镖击中它。
我创建了一个实现 runnable 的 DartTosser 类,以抛出需要抛出的飞镖总数的增量。我创建了一个带有实例字段的对象和一个同步方法来聚合来自多个 DartTossers 的 dart 命中。投完所有飞镖后,将估计并返回 pi。
从用户输入中读取线程数和投掷次数。然后按下按钮触发以下方法:
private double estimatePi(int numThreads, long numTosses, TossBin bin){
long tossIncrement = numTosses/numThreads;
ExecutorService executor = Executors.newFixedThreadPool(numThreads);
for (int i = 0; i < numThreads; i++){
executor.submit(new DartTosser(i, tossIncrement, bin));
}
executor.shutdown();
System.out.println("All dart tossers have begun tossing darts.");
try {
executor.awaitTermination(1, TimeUnit.DAYS);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("All darts have been tossed.");
return (4*bin.getTotalInCircle())/((double)numTosses);
}
DartTosser 类在其 run() 方法中触发以下方法,然后将击中圆圈的总投掷次数添加到 TossBin 对象的实例中:
private long startTossing(){
for (int i = 0; i < localTosses; i++){
// get two random doubles between -1 and 1
x = generateRandomNumber();
y = generateRandomNumber();
distanceSquared = (x*x) + (y*y);
if (distanceSquared <= 1.0){
tossesInCircle++;
}
}
return tossesInCircle;
}
为了完整起见,这就是我的 TossBin 类的样子:
public class TossBin {
private long totalTossesInCircle = 0;
public TossBin(){
}
public synchronized void addToTotalTosses(long n){
this.totalTossesInCircle += n;
}
public void resetTossValues(){
this.totalTossesInCircle = 0;
}
public long getTotalInCircle(){
return totalTossesInCircle;
}
}
PI 近似值很接近,所以我认为我的实际计算很好。运行单个线程,它将在大约 1600 毫秒左右处理 100 万次抛掷。运行两个线程,它将在大约 5600 毫秒左右处理 100 万次抛掷。线程越多,效率越低。我可以从系统输出中看到线程(似乎是)并发运行,但我的并行化显然是各种各样的。
我在 Galaxy S3 以及 eclipse 的模拟器上运行它,我看到了同样的总体趋势。有什么想法吗?
只是为了确保我已经晾干了所有可能脏的床单:
public class DartTosser implements Runnable {
private int id;
private long localTosses = 0;
private long tossesInCircle = 0;
double x, y, distanceSquared;
TossBin globalBin;
private double generateRandomNumber(){
return (Math.random()*2.0)-1.0;
}
public DartTosser(int id, long tosses, TossBin globalBin){
this.id = id;
this.localTosses = tosses;
this.globalBin = globalBin;
}
private long startTossing(){
for (int i = 0; i < localTosses; i++){
// get two random doubles between -1 and 1
x = generateRandomNumber();
y = generateRandomNumber();
distanceSquared = (x*x) + (y*y);
if (distanceSquared <= 1.0){
tossesInCircle++;
}
}
return tossesInCircle;
}
@Override
public void run() {
System.out.println("Dart tosser number " + Integer.toString(id) + "starting work.");
globalBin.addToTotalTosses(startTossing());
System.out.println("Dart tosser number " + Integer.toString(id) + "finished work.");
}
}