任务DAG遍历,拓扑排序

0、定义

DAG:有向无环图

根据定义,可以得到以下两个结论:

  1. 如果图G中存在环(即G不是有向无环图),那么G不存在拓扑排序,反之如果G存在拓扑排序,则G中没有环
  2. 如果G是有向无环图,那么他的拓扑排序可能不止一种
  3. 拓扑排序的图,一定是有向无环图
  4. 有向无环图,一定能拓扑排序

1、分页遍历所有任务,同时根据任务的依赖关系,生成dag图

@Data
public class TaskDagGraphBO {
    private Set nodes = new HashSet<>();
    private List edges = new ArrayList<>();

    public TaskDagGraphBO() {
    }

    public TaskDagGraphBO(Long nodesSize) {
        this.nodes = new HashSet<>(Integer.parseInt(nodesSize+""));
    }

    public void addNode(Long node) {
        if(!this.nodes.contains(node)){
            this.nodes.add(node);
        }
    }

    public void addNodes(List nodes) {
        this.nodes.addAll(nodes);
    }

    public void addEdge(Long from, Long to) {
        Optional any = this.edges.stream().filter(e -> e.getFrom().equals(from) && e.getTo().equals(to)).findAny();
        if(!any.isPresent()){
            TaskDagEdge taskDagEdge = new TaskDagEdge(from, to);
            this.edges.add(taskDagEdge);
        }
    }

    public void remove(Long node) {
        this.nodes.remove(node);
        edges.removeIf(taskDagEdge -> taskDagEdge.getFrom().equals(node) || taskDagEdge.getTo().equals(node));
    }
}
public class TaskDagEdge{
    Long from;
    Long to;

    public TaskDagEdge(java.lang.Long start, java.lang.Long end) {
        this.from = start;
        this.to = end;
    }

    public Long getFrom() {
        return (Long) from;
    }

    public void setFrom(Long from) {
        this.from = from;
    }

    public Long getTo() {
        return (Long) to;
    }

    public void setTo(Long to) {
        this.to = to;
    }
}

使用:先添加所有节点,再添加边

 taskDagGraphBO.addNode(info.getTaskBasicInfo().getId());

 // 根据task依赖生成边
 taskDagGraphBO.addEdge(t.getTaskId(), info.getTaskBasicInfo().getId());

2、排序(广度优先)

  • 从 DAG 图中选择入度为的顶点(即没有节点指向该节点)并输出。
  • 从图中删除这个节点以及由他发出的有向边,同时针对该节点指向的子节点的入度减一。
  • 重复第一步和第二步,直到当前的 DAG 图为空或当前图中不存在无前驱的顶点为止。
  • 代码需要优化点为:第2步中,子节点入度减一时,不需要重新计算所有节点入度
  • 存在环判断:节点数不相等时
@Slf4j
public class TaskDAGUtil {

    public static List findPriority1(TaskDagGraphBO graph) {
        long start = System.nanoTime();
        int size = graph.getNodes().size();

        List res = new ArrayList<>();
        Queue queue = new LinkedList<>();
        Map inDegree = getInDegree(graph);

        inDegree.forEach((k,v)->{
            if(v.equals(0)){
                queue.add(k);
            }
        });

        while (!queue.isEmpty()) {
            Long cur = queue.poll();
            res.add(cur);

            graph.remove(cur);
            inDegree = getInDegree(graph);
            inDegree.forEach((k,v)->{
                if(v.equals(0)){
                    if(!queue.contains(k)) {
                        queue.add(k);
                    }
                }
            });
        }
        log.info("taskmigrete.taskdag.sort.time:{}inDegree:{}",System.nanoTime()-start,inDegree);

        // 若排序后节点小于 n,说明存在环
        return res.size() == size ? res : null;
    }

    /**
     * 始终寻找入度为0的点,直到所有节点加入结果队列
     *
     * @param graph
     * @return
     */
    public static List findPriority(TaskDagGraphBO graph) {
        List list = new ArrayList<>();
        Set nodes = graph.getNodes();
        Map inDegree = getInDegree(graph);
        int size = nodes.size();
        int count = 0;
        while (count < size && inDegree.keySet().size() != 0) {
            log.info("Finding priority:{}");
            for (Map.Entry entry : inDegree.entrySet()) {
                log.info("Finding inDegree iterator:{}",entry);
                Long key = entry.getKey();
                if (entry.getValue() == 0) {
                    list.add(key);
                    count++;
                    graph.remove(key);
                    inDegree = getInDegree(graph);
                }
            }
        }
        return list;
    }

    /**
     * 获取图中节点的入度
     *
     * @param graph
     * @return
     */
    public static Map getInDegree(TaskDagGraphBO graph) {
        Set nodes = graph.getNodes();
        List connectTable = graph.getEdges();
        Map map = new ConcurrentHashMap<>();
        for (Long node : nodes) {
            map.put(node, 0);
        }

        for (TaskDagEdge taskDagEdge : connectTable) {
            map.computeIfPresent(taskDagEdge.getTo(), (k, v) -> v + 1);
        }
        log.info("Finding inDegree:{}",map);
        return map;
    }

    public static void main(String[] args) {
        String s = "{\n" +
                "\t\"edges\": [{\n" +
                "\t\t\"from\": 1631269768021229570,\n" +
                "\t\t\"to\": 1651533478953267521\n" +
                "\t}, {\n" +
                "\t\t\"from\": 1655549249384906369,\n" +
                "\t\t\"to\": 1651533478953267521\n" +
                "\t}, {\n" +
                "\t\t\"from\": 1656941044568217217,\n" +
                "\t\t\"to\": 1656941044568184449\n" +
                "\t}, {\n" +
                "\t\t\"from\": 1656941044568209025,\n" +
                "\t\t\"to\": 1656941044568184449\n" +
                "\t}, {\n" +
                "\t\t\"from\": 1656941044568331905,\n" +
                "\t\t\"to\": 1656941044568184449\n" +
                "\t}, {\n" +
                "\t\t\"from\": 1656941044568217217,\n" +
                "\t\t\"to\": 1656941044568200833\n" +
                "\t}, {\n" +
                "\t\t\"from\": 1656941044568217217,\n" +
                "\t\t\"to\": 1656941044568209025\n" +
                "\t}, {\n" +
                "\t\t\"from\": 1656941044568200833,\n" +
                "\t\t\"to\": 1656941044568209025\n" +
                "\t}, {\n" +
                "\t\t\"from\": 1656941044568200833,\n" +
                "\t\t\"to\": 1656941044568331905\n" +
                "\t}],\n" +
                "\t\"nodes\": [1656941044568331905, 1628668617357041665, 1628655409208832002, 1656941044568184449, 1656941044568192641, 1656941044568200833, 1656941044568209025, 1656941044568217217, 1631269768021229570, 1655772785192377409, 1631476828683976706, 1651533478953267521, 1627858007982931970, 1655549249384906369]\n" +
                "}";

        String ege = "[{\n" +
                "\t\t\"from\": 1631269768021229570,\n" +
                "\t\t\"to\": 1651533478953267521\n" +
                "\t}, {\n" +
                "\t\t\"from\": 1655549249384906369,\n" +
                "\t\t\"to\": 1651533478953267521\n" +
                "\t}, {\n" +
                "\t\t\"from\": 1656941044568217217,\n" +
                "\t\t\"to\": 1656941044568184449\n" +
                "\t}, {\n" +
                "\t\t\"from\": 1656941044568209025,\n" +
                "\t\t\"to\": 1656941044568184449\n" +
                "\t}, {\n" +
                "\t\t\"from\": 1656941044568331905,\n" +
                "\t\t\"to\": 1656941044568184449\n" +
                "\t}, {\n" +
                "\t\t\"from\": 1656941044568217217,\n" +
                "\t\t\"to\": 1656941044568200833\n" +
                "\t}, {\n" +
                "\t\t\"from\": 1656941044568217217,\n" +
                "\t\t\"to\": 1656941044568209025\n" +
                "\t}, {\n" +
                "\t\t\"from\": 1656941044568200833,\n" +
                "\t\t\"to\": 1656941044568209025\n" +
                "\t}, {\n" +
                "\t\t\"from\": 1656941044568200833,\n" +
                "\t\t\"to\": 1656941044568331905\n" +
                "\t}]";
        JSONArray objects = JSONArray.parseArray(ege);
        List taskDagEdges = new ArrayList<>(objects.size());

        for(int i=0;i(){});
        taskDagGraphBO.setEdges(taskDagEdges);
        List priority1 = TaskDAGUtil.findPriority1(taskDagGraphBO);
        System.out.println(priority1);
    }

}

你可能感兴趣的:(任务调度,任务dag)