Параллельное выполнение узлов графа (Задач) и поиск критических Задач

Я реализовал ориентированный граф на Java. Это для планировщика проекта, и один узел представляет задачу с разными свойствами. Я успешно реализовал топологическую сортировку, но мне нужен способ запускать / выполнять параллельные задачи, как только зависимости для задачи будут выполнены.

Вот моя реализация:

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

Содержимое house.txt: Первая строка (число) - это максимальное количество узлов / задач. Столбцы: номер задачи, имя, время, необходимое для выполнения, требования к персоналу, границы зависимости (завершаются 0).

8
1   Build-walls     4 2       5       0
2   Build-roofs     6 4       1       0
3   Put-on-wallpapers   1 2       1       2       0
4   Put-on-tiles        1 3       2       0
5   Build-foundation    4 2       0
6   Make-floor          2 2       5       0
7   Put-carpet-floor    4 2       6       2       0
8   Move-in         4 4       3       7       0

Задачи без входящих ребер (т. Е. Без зависимостей) должны быть запущены в первую очередь. Выполнение задач должно быть напечатано, например, как и для ввода выше:

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

и Т. Д.


person Susinthiran    schedule 23.10.2013    source источник
comment
Если Task реализует Runnable, вы можете использовать ExecutorService, чтобы запустить его.   -  person Fildor    schedule 23.10.2013
comment
Филдор: К сожалению, мне приходится реализовывать алгоритм вручную, и я не могу использовать Runnable.   -  person Susinthiran    schedule 23.10.2013
comment
Тогда уточните, что означает выполнение задачи именно в вашем случае. Вы хотите рассчитать дискретное время начала и окончания для каждой задачи и узнать критический путь?   -  person Fildor    schedule 23.10.2013
comment
если на графике есть цикл, он обнаруживается topSort () и выдается сообщение о том, что проект нереализуем. Каждую задачу следует запускать как можно скорее, то есть после того, как все задачи, от которых она зависит, будут выполнены. Задачи вне зависимости нужно запускать сразу. Выходные данные должны быть снова предоставлены путем распечатки важной информации, например, когда задачи запускаются и / или заканчиваются. Ваша система также должна распечатывать текущий штат сотрудников в эти моменты времени. Для выполнения моих задач обратная связь от системы должна быть такой, как указано в списке порядка выполнения задач :)   -  person Susinthiran    schedule 23.10.2013
comment
Речь идет об оптимизации обхода на основе времени узла и учета зависимостей :)   -  person Susinthiran    schedule 23.10.2013
comment
Отвечает ли это на ваш вопрос? Выполнение направленного ациклического графа задач параллельно   -  person Anmol Singh Jaggi    schedule 08.05.2021


Ответы (3)


Если это кому-то поможет, то это как раз тот вариант использования библиотеки JavaRed - планирование и выполнение асинхронных задач. в потоке, определяемом как граф.

Короче говоря, такой сложный поток графа, как этот:  Схема выполнения графика

можно просто реализовать с помощью:

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));

Подробнее об этом читайте в вики проекта.

person Aviv Carmi    schedule 24.04.2017

Есть несколько способов.

Вы можете использовать Java 8 CompletableFuture или Guava ListenableFuture для его реализации.

Ваша задача должна реализовывать Runnable или Callable. когда вы выполняете текущую задачу, вы должны выполнять ее preTasks рекурсивно (если задача в составном режиме, она будет знать своего предшественника) и убедиться, что они выполнены (с помощью флага для выражения статуса или чего-то еще).

Вот так:

CompletableFuture.allOf(predecessor).thenRunAsync(current)...
Futures.allAsList(predecessor)...
person RoniZeng    schedule 20.02.2021

Чтобы запланировать свои задачи, вы можете либо самостоятельно поддерживать пул потоков, либо получить библиотеку, которая сделает это за вас. Если вы сами поддерживаете пул потоков, это очень просто (простите за плохой псевдокод):

assume you already have tasks topoligically sorted : t0,t1,t2,....,tn
int next_task=0;  //global pointer to next task

then in each thread, you do:
    while (true) {
        atomic {
            if (next_task > n) break;
            t = get_task (next_task);
            next_task = next_task + 1;
        }
        run task t;
    }

Таким образом, вы выполняете все задачи в порядке, учитывающем их зависимости, и каждый поток перейдет к следующей задаче, как только завершит последнюю.

Если вы хотите иметь библиотеку, чтобы запланировать это для вас, возможно, OpenMP, TBB или посмотрите этот поток Как реализовать планировщик, подобный DAG, на Java??

Надеюсь это поможет.

person lindenrovio    schedule 18.01.2014