Java 并行执行图节点(任务)并查找关键任务
我已经用Java实现了一个有向图。它适用于项目计划员,一个节点表示具有不同属性的任务。我已经成功地实现了拓扑排序,但是我需要一种方法来在任务的依赖项完成后立即运行/执行并行任务 以下是我的实现:Java 并行执行图节点(任务)并查找关键任务,java,algorithm,directed-graph,Java,Algorithm,Directed Graph,我已经用Java实现了一个有向图。它适用于项目计划员,一个节点表示具有不同属性的任务。我已经成功地实现了拓扑排序,但是我需要一种方法来在任务的依赖项完成后立即运行/执行并行任务 以下是我的实现: import java.util.ArrayList; import java.util.List; import java.util.*; public class Task implements Comparable<Task> { int number; String
import java.util.ArrayList;
import java.util.List;
import java.util.*;
public class Task implements Comparable<Task> {
int number;
String name;
int time;
int staff;
int earliestStart, latestStart;
List<Integer> dependencies;
List<Task> outEdges;
int cntPredecessors;
Status status;
public enum Status {UNVISITED,RUNNING,VISITED};
@Override
public String toString() {
return "Task{" +
"number=" + number +
", name='" + name + '\'' +
", time=" + time +
", staff=" + staff +
", dependencies=" + dependencies +
'}';
}
public Task(int number, String name, int time, int staff) {
setNumber(number);
setName(name);
setTime(time);
setStaff(staff);
dependencies=new ArrayList<>();
outEdges=new ArrayList<>();
status = Status.UNVISITED;
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getTime() {
return time;
}
public void setTime(int time) {
this.time = time;
}
public int getStaff() {
return staff;
}
public void setStaff(int staff) {
this.staff = staff;
}
public List<Integer> getDependencies() {
return dependencies;
}
public void setDependencies(List<Integer> dependencies) {
this.dependencies = dependencies;
}
public List<Task> getOutEdges() {return outEdges; }
public void setOutEdge(Task t) {outEdges.add(t); }
public int getIndegrees() { return cntPredecessors; }
public void setIndegree() { cntPredecessors = dependencies.size();}
public Status getStatus() {return this.status; }
public Task findTaskWithNoInDegree() {
if (this.cntPredecessors == 0) return this;
return null;
}
public int compareTo(Task other) {
return Integer.compare(this.time, other.time);
}
} //END class Task
// The class Main represents the Task objects in a graph
import java.util.*;
public class Main {
static int maxnr = 0;
public static void main(String[] args) {
Map<Integer, Task> map=new HashMap<>();
Scanner scanner = new Scanner(Main.class.getResourceAsStream("/res/house.txt"), "UTF-8");
Main mainObject = new Main();
map = mainObject.fromScanner(scanner);
System.out.println("DEBUG: maxnr " + maxnr);
mainObject.setInDegrees(map);
mainObject.setOutEdges(map);
//System.out.println("DEBUG: Size of outEdges for Task 1 is : " + map.get(1).getOutEdges().size());
//System.out.println("DEBUG: Indegrees for Task 8 is : " + map.get(8).getIndegrees());
mainObject.topSort(maxnr,map);
for(Integer k:map.keySet()) {
//System.out.println("DEBUG outEdges for Task number " + map.get(k).getNumber() + " " + map.get(k).getOutEdges());
}
} // END of void main(String[] args)
public void setInDegrees(Map<Integer, Task> map) {
for(Integer k:map.keySet()) {
Task task = map.get(k);
task.setIndegree();
}
}
public void setOutEdges(Map<Integer, Task> map) {
for(Integer k:map.keySet()) {
// map.get(k).setIndegrees();
for(Integer dep:map.get(k).getDependencies()) {
//System.out.println("DEBUG: "+ dep);
//System.out.print(" DEBUG: Name is " + map.get(dep).getName());
map.get(dep).setOutEdge(map.get(k));
}
//System.out.println(map.get(k));
}
} //END of setOutEdges()
// toplogical sort # Big O(|V| +|E|) for indegree calc and since the code only looks at each edge once!
// S is Set of all nodes with no incoming edges
public void topSort(int maxnr, Map<Integer, Task> map) {
ArrayList<Task> L = new ArrayList<Task>(maxnr);
//LinkedList<Task> L = new LinkedList<>();
//HashSet<Task> S = new HashSet<>(maxnr);
LinkedList<Task> S = new LinkedList<>();
for(Integer n:map.keySet()) {
if(map.get(n).getIndegrees() == 0) {
S.add(map.get(n));
}
}
System.out.println("DEBUG: Set S is " + S);
//HashSet<Task> S2 = new HashSet<>(S);
Task t;
int counter= 0;
while(!S.isEmpty()) {
//System.out.print("Topsort: Task and S. " + t.getNumber());
t = S.iterator().next();
S.remove(t);
//System.out.print("Topsort : " + t.getNumber());
L.add(t);
//System.out.println("Starting " + t.getNumber());
counter++;
for(Iterator<Task> it = t.outEdges.iterator(); it.hasNext();) {
Task w = it.next();
w.cntPredecessors--;
if (w.getIndegrees() == 0) {
S.add(w);
// System.out.println("Starting " + w.getNumber());
}
}
}
System.out.println();
if (counter < maxnr) {
System.out.println("Cycle detected, topsort not possible");
} else {
//System.out.println("Topsort : " + Arrays.toString(L.toArray()));
Iterator<Task> topsortIt = L.iterator();
System.out.print("\n Topsort list is: ");
while (topsortIt.hasNext()) {
System.out.print(" " + topsortIt.next().getNumber());
}
System.out.println();
}
} //END of topSort()
public Map fromScanner(Scanner scanner) {
Map<Integer, Task> map=new HashMap<>();
maxnr = scanner.nextInt();
while (scanner.hasNextLine()) {
String line=scanner.nextLine();
if (line.isEmpty() ) continue;
Scanner s2=new Scanner(line);
Task task = new Task(s2.nextInt(), s2.next(), s2.nextInt(), s2.nextInt());
while (s2.hasNextInt()) {
int i = s2.nextInt();
if (i != 0) {
task.getDependencies().add(i);
}
}
map.put(task.getNumber(), task);
}
return map;
} //END of fromScanner()
} //END of class Main
应首先启动没有传入边(即没有依赖项)的任务。
例如,应打印任务的执行情况,如上面给出的输入:
Time: 0 Starting: 5 // Task 5 only one with no dependencies
Current staff: 2
Time: 4 Finished: 5
Starting: 6
Starting: 1
Current staff: 4 // sum of manpower from Task 6 and 1 => 2 + 2 = 4
Time: 6 Finished: 6
Current staff: 2
Time: 8 Finished: 1
Finished: 1
Starting: 2
Starting: 3
Current staff: 6
等等。要安排任务,您可以自己维护线程池,也可以让一个库为您完成任务。如果您自己维护线程池,它非常简单(请原谅这个糟糕的伪代码): 这样,所有任务的执行顺序都与它们的依赖关系有关,每个线程在完成最后一个任务后都将跳转到下一个任务 如果你想有一个库为你安排它,也许OpenMP,TBB,或者看看这个线程
希望这有帮助 如果它对任何人都有帮助,那么这正是在定义为图的流中调度和运行异步任务的用例 简言之,像这样复杂的图形流: 可通过以下方式简单实现:
Result<String> aResult = produceFutureOf(String.class).byExecuting(() -> executeA());
Result<String> bResult = ifResult(aResult).succeed().produceFutureOf(String.class).byExecuting(a -> executeB(a));
Result<String> cResult = ifResult(aResult).succeed().produceFutureOf(String.class).byExecuting(a -> executeC(a));
Result<String> eResult = ifResult(aResult).succeed().produceFutureOf(String.class).byExecuting(a -> executeE(a));
Result<String> dResult = ifResults(bResult, cResult).succeed().produceFutureOf(String.class).byExecuting((b, c) -> executeD(b, c));
Result<String> fResult = ifResult(eResult).succeed().produceFutureOf(String.class).byExecuting(e -> executeF(e));
Result<String> gResult = ifResult(fResult).succeed().produceFutureOf(String.class).byExecuting(f -> executeG(f));
return ifResults(dResult, gResult).succeed().produceFutureOf(String.class).byExecuting((d, g) -> executeH(d, g));
Result aResult=produceFutureOf(String.class).byExecuting(()->executeA());
Result bResult=ifResult(aResult).succeed().produceFutureOf(String.class).byExecuting(a->executeB(a));
Result cResult=ifResult(aResult).success().produceFutureOf(String.class).byExecuting(a->executeC(a));
Result-eResult=ifResult(aResult).succeed().produceFutureOf(String.class).byExecuting(a->executeE(a));
Result dResult=ifResults(bResult,cResult).succeed().produceFutureOf(String.class).byExecuting((b,c)->executeD(b,c));
Result fResult=ifResult(eResult).succeed().produceFutureOf(String.class).byExecuting(e->executeF(e));
Result gResult=ifResult(fResult).succeed().produceFutureOf(String.class).byExecuting(f->executeG(f));
通过执行((d,g)->executeH(d,g)),返回ifResults(dResult,gResult).succeed().produceFutureOf(String.class);
有关它的更多信息,请参见有几种方法 您可以使用Java8
CompletableFuture
或GuavaListenableFuture
来实现它
您的任务应该实现Runnable
或Callable
。当您执行当前任务时,您应该递归地执行它的预任务
(如果任务是复合模式,它将知道它的前置任务),并确保它们已完成(通过标志来表示状态或其他)
像这样:
CompletableFuture.allOf(predecessor).thenRunAsync(current)...
Futures.allAsList(predecessor)...
如果
Task
实现了Runnable
,您可以使用一个来运行它。Fildor:不幸的是,我必须手动实现算法,不能使用Runnable。那么请详细说明“执行任务”在您的情况下的确切含义。是否要计算每个任务的离散开始时间和结束时间,并找出关键路径?如果图中有一个循环,则topSort()会检测到该循环,并给出一条消息,说明项目无法实现。应尽快启动每个任务,即在它所依赖的所有任务完成后启动。没有依赖关系的任务应该立即启动。应通过打印重要信息(即任务启动和/或结束时)再次提供输出。您的系统还应及时打印出当前的工作人员。对于我的任务执行,来自系统的反馈应该如任务执行顺序列表中所示:)它是关于根据节点的时间优化遍历并考虑依赖关系:)
Result<String> aResult = produceFutureOf(String.class).byExecuting(() -> executeA());
Result<String> bResult = ifResult(aResult).succeed().produceFutureOf(String.class).byExecuting(a -> executeB(a));
Result<String> cResult = ifResult(aResult).succeed().produceFutureOf(String.class).byExecuting(a -> executeC(a));
Result<String> eResult = ifResult(aResult).succeed().produceFutureOf(String.class).byExecuting(a -> executeE(a));
Result<String> dResult = ifResults(bResult, cResult).succeed().produceFutureOf(String.class).byExecuting((b, c) -> executeD(b, c));
Result<String> fResult = ifResult(eResult).succeed().produceFutureOf(String.class).byExecuting(e -> executeF(e));
Result<String> gResult = ifResult(fResult).succeed().produceFutureOf(String.class).byExecuting(f -> executeG(f));
return ifResults(dResult, gResult).succeed().produceFutureOf(String.class).byExecuting((d, g) -> executeH(d, g));
CompletableFuture.allOf(predecessor).thenRunAsync(current)...
Futures.allAsList(predecessor)...