背景
所以我正在编写一个应用程序,旨在执行蒙特卡罗模拟,以研究可以通过Moran过程(进化图论)进化的图形。对于无方向图,这可以很好地工作,但对于有向图,应用程序一直表现出奇怪的行为,我不能为我的生活找出原因。似乎发生的情况是,当此布尔变量isDirected设置为true时,线程会在满足循环条件之前退出它们运行的for循环,尽管isDirected为false时正常工作。
图表由邻接矩阵表示,因此图表定向时代码的唯一区别是邻接矩阵是非对称的,但我看不出任何会产生影响的原因。
代码
主要相关代码是控制器的这一部分:
//Initialise a threadPool and an array of investigators to provide each thread with an Investigator runnable
long startTime = System.nanoTime();
int numThreads = 4;
Investigator[] invArray = new Investigator[numThreads];
ExecutorService threadPool = Executors.newFixedThreadPool(numThreads);
//Assign the tasks to the threads
for(int i=0;i<numThreads;i++){
invArray[i] = new Investigator(vertLimit,iterations,graphNumber/numThreads,isDirected,mutantFitness,vertFloor);
threadPool.submit(invArray[i]);
}
threadPool.shutdown();
//Wait till all the threads are finished, note this could cause the application to hang for the user if the threads deadlock
try{
threadPool.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
}catch(InterruptedException except){
System.out.println("Thread interrupted");
}
//The next two blocks average the results of the different threads into 1 array
double[] meanArray = new double[vertLimit];
double[] meanError = new double[vertLimit];
double[] fixProbArray = new double[vertLimit];
double[] fixProbError = new double[vertLimit];
for(int x=0;x<vertLimit;x++){
for(Investigator i:invArray){
meanArray[x] += i.getMeanArray()[x];
meanError[x] += Math.pow(i.getMeanError()[x], 2);
fixProbArray[x] += i.getFixProbArray()[x];
fixProbError[x] += Math.pow(i.getFixProbError()[x], 2);
}
meanArray[x] = meanArray[x]/numThreads;
fixProbArray[x] = fixProbArray[x]/numThreads;
meanError[x] = Math.sqrt(meanError[x]);
fixProbError[x] = Math.sqrt(fixProbError[x]);
}
long endTime = System.nanoTime();
//The remaining code is for printing and producing graphs of the results
与Investigator类一样,其重要部分如下所示:
public class Investigator implements Runnable{
public Investigator(int vertLimit,int iterations,int graphNumber,Boolean isDirected,int mutantFitness,int... vertFloor){
//Constructor just initialises all the class variables passed in
}
public void run(){
GraphGenerator g = new GraphGenerator();
Statistics stats = new Statistics();
//The outer loop iterates through graphs with increasing number of vertices, this is the problematic loop that exits too early
for(int x = vertFloor>2?vertFloor:2; x < vertLimit; x++){
System.out.println("Current vertex amount: " + x);
double[] currentMean = new double[graphNumber];
double[] currentMeanErr = new double[graphNumber];
double[] currentFixProb = new double[graphNumber];
double[] currentFixProbErr = new double[graphNumber];
//This loop generates the required number of graphs of the given vertex number and performs a simulation on each one
for(int y=0;y<graphNumber;y++){
Simulator s = new Simulator();
matrix = g.randomGraph(x, isDirected, mutantFitness);
s.moranSimulation(iterations, matrix);
currentMean[y] = stats.freqMean(s.getFixationTimes());
currentMeanErr[y] = stats.freqStandError(s.getFixationTimes());
currentFixProb[y] = s.getFixationProb();
currentFixProbErr[y] = stats.binomialStandardError(s.getFixationProb(), iterations);
}
meanArray[x] = Arrays.stream(currentMean).sum()/currentMean.length;
meanError[x] = Math.sqrt(Arrays.stream(currentMeanErr).map(i -> i*i).sum());
fixProbArray[x] = Arrays.stream(currentFixProb).sum()/currentFixProb.length;
fixProbError[x] = Math.sqrt(Arrays.stream(currentFixProbErr).map(i -> i*i).sum());;
}
}
//A number of getter methods also provided here
}
问题
我已经输入了一些打印语句来解决发生的事情,并且出于某种原因,当我将isDirected设置为true时,线程在x到达vertLimit之前完成(我已经检查过它确实是我指定的值)。我已经尝试手动使用我的GraphGenerator.randomGraph()方法进行有向图,并且它提供了正确的输出以及测试Simulator.moranSimulation(),当手动调用时,它对于有向图也很好用,我没有得到线程中断被我的catch块捕获,所以这也不是问题。
对于同一组参数,线程在看似随机的不同阶段完成,有时它们在停止时都处于相同的x值,有时一些线程将比其他线程更远但是从运行中更改跑。
我完全被这里难过,非常感谢你的帮助,谢谢。
答案 0 :(得分:0)
看起来你可能会使用threadPool.shutdown()过早地终止线程;
来自文件: 此方法不会等待先前提交的任务完成执行。使用awaitTermination来做到这一点。
代码在awaitTermination之前调用.shutdown ......
答案 1 :(得分:0)
当ExecutorService正在运行任务时,如果抛出未处理的异常,它们有时会过早地结束。
每次拨打.submit(Runnable)或.submit(Callable)时,都会收到一个Future对象,表示该任务的最终完成情况。 Future对象有一个.get()方法,它将在任务完成时返回任务结果。调用此方法将阻塞,直到该结果可用。此外,如果任务抛出了任务代码未处理的异常,则对.get()的调用将抛出ExecutionException,它将包装实际抛出的异常。
如果您的代码由于未处理的异常而提前退出,请在提交执行任务时(在提交了您希望的所有任务之后)获取的每个Future对象上调用.get()并捕获任何ExecutionExceptions恰好被抛出来弄清楚实际的潜在问题是什么。