it-swarm.com.ru

Оптимизированный алгоритм для планирования задач с зависимостью?

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

например:

  1. A -> B
  2. A -> C
  3. B -> D
  4. E -> F

Таким образом, один из способов запустить это - запустить 1, 2 и 4 параллельно. Вслед за 3.

Другой способ может быть Запустить 1 и затем запустить 2, 3 и 4 параллельно.

Другой может быть запущен 1 и 3 последовательно, 2 и 4 параллельно.

Есть идеи?

20
user2186138

Пусть каждая задача (например, A,B,...) будет узлами в направленном ациклическом графе и определит дуги между узлами на основе вашего 1,2,...

http://en.wikipedia.org/wiki/Topological_sorting

Затем вы можете топологически упорядочить свой график (или использовать метод поиска, например BFS ). В вашем примере C<-A->B->D и E->F, следовательно, A & E имеют глубину 0 и должны быть запущены первыми. Затем вы можете запустить F, B и C параллельно, а затем D.

Также взгляните на PERT .

Обновление:

Как вы узнаете, имеет ли B более высокий приоритет, чем F?

Это интуиция топологической сортировки, используемая для нахождения порядка. 

Сначала он находит корневые (без входящих ребер) узлы (поскольку они должны существовать в группе обеспечения доступности баз данных). В вашем случае это A & E. Это решает первый раунд работ, которые должны быть завершены. Затем, дочерние элементы корневых узлов (B, C и F) должны быть завершены. Это легко получить, запросив график. Затем процесс повторяется до тех пор, пока не будут найдены (завершены) узлы (задания).

11
Jacob

Учитывая отображение между элементами и элементами, от которых они зависят, топологическая сортировка упорядочивает элементы так, чтобы ни один элемент не предшествовал элементу, от которого она зависит.

Эта задача кода Rosetta имеет решение на Python которая может сказать вам, какие элементы доступны для параллельной обработки.

С учетом вашего ввода код становится:

try:
    from functools import reduce
except:
    pass

data = { # From: http://stackoverflow.com/questions/18314250/optimized-algorithm-to-schedule-tasks-with-dependency
    # This   <-   This  (Reverse of how shown in question)
    'B':         set(['A']),
    'C':         set(['A']),
    'D':         set(['B']),
    'F':         set(['E']),
    }

def toposort2(data):
    for k, v in data.items():
        v.discard(k) # Ignore self dependencies
    extra_items_in_deps = reduce(set.union, data.values()) - set(data.keys())
    data.update({item:set() for item in extra_items_in_deps})
    while True:
        ordered = set(item for item,dep in data.items() if not dep)
        if not ordered:
            break
        yield ' '.join(sorted(ordered))
        data = {item: (dep - ordered) for item,dep in data.items()
                if item not in ordered}
    assert not data, "A cyclic dependency exists amongst %r" % data

print ('\n'.join( toposort2(data) ))

Который затем генерирует этот вывод:

A E
B C F
D

Элементы в одной строке вывода могут быть обработаны в любом подзаказе или, действительно, параллельно; до тех пор, пока все элементы более высокой строки обрабатываются до элементов следующих строк, чтобы сохранить зависимости.

7
Paddy3118

Ваши задачи - это ориентированный граф без (надеюсь) циклов.

I содержит sources и wells (источники, являющиеся задачами, которые не зависят (не имеют входящего Edge), а скважины являются задачами, которые не разблокируют ни одну задачу (без исходящего Edge)).

Простым решением было бы отдать приоритет вашим задачам на основе их полезности (давайте назовем это U.

Обычно, начиная с лунок, они имеют полезность U = 1, потому что мы хотим, чтобы они закончили.

Поместите все предшественники скважин в список L текущего оцениваемого узла.

Затем, принимая каждый узел в L, его значение U является суммой значений U узлов, которые зависят от него + 1. Поместите всех родителей текущего узла в список L

Цикл, пока все узлы не будут обработаны.

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

В вашем примере 

U(C) = U(D) = U(F) = 1
U(B) = U(E) = 2
U(A) = 4

Это означает, что вы начнете A сначала с E, если это возможно, затем B и C (если это возможно), затем D и F

1
njzk2

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

для теоретической точки зрения, эта статья охватывает тему.

1
collapsar

Без учета последовательного/параллельного аспекта проблемы этот код может по крайней мере определить общее последовательное решение:

def order_tasks(num_tasks, task_pair_list):
    task_deps= []
    #initialize the list
    for i in range(0, num_tasks):
        task_deps[i] = {}

    #store the dependencies
    for pair in task_pair_list:
        task = pair.task
        dep = pair.dependency

        task_deps[task].update({dep:1})

    #loop through list to determine order
    while(len(task_pair_list) > 0):
        delete_task = None

        #find a task with no dependencies
        for task in task_deps:
            if len(task_deps[task]) == 0:
                delete_task = task
                print task
                task_deps.pop(task)
                break

        if delete_task == None:
            return -1

        #check each task's hash of dependencies for delete_task
        for task in task_deps:
            if delete_key in task_deps[task]:
                del task_deps[task][delete_key]

    return 0

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

0
flyerfye