优化算法来安排具有依赖性的任务?

时间:2013-08-19 12:51:43

标签: algorithm scheduled-tasks scheduling

有些任务从文件中读取,执行某些处理并写入文件。这些任务将根据依赖性进行调度。此外,任务可以并行运行,因此需要优化算法以串行运行相关任务,并尽可能并行运行。

例如:

  1. A - >乙
  2. A - > ç
  3. B - > d
  4. E - > ˚F
  5. 因此,运行此方法的一种方法就是运行 1,2和& 4并行。其次是3。

    另一种方式可能是 运行1然后运行2,3& 4并行。

    另一个可以串行运行1和3,并行运行2和4。

    有什么想法吗?

5 个答案:

答案 0 :(得分:11)

让每个任务(例如A,B,...)成为directed acyclic graph中的节点,并根据您的1,2,...定义节点之间的弧。

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

然后,您可以topologically order使用图表(或使用基于搜索的方法,如BFS)。在您的示例中,C<-A->B->DE->F因此A&amp; E的深度为0,需要先运行。然后,您可以并行运行FBC,然后D

另外,请查看PERT

更新

您如何知道B的优先级是否高于F

这是用于查找排序的拓扑排序背后的直觉。

它首先找到根(没有传入边)节点(因为DAG中必须存在一个)。在你的情况下,那是A&amp; E。这解决了需要完成的第一轮工作。接下来,需要完成根节点(BCF)的子节点。通过查询图表可以轻松获得此信息。然后重复该过程,直到找不到(完成)节点(作业)。

答案 1 :(得分:7)

给定项目之间的映射以及它们所依赖的项目,拓扑排序会对项目进行排序,以使项目不在其所依赖的项目之前。

This Rosetta code tasksolution in 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

输出的一行上的项目可以按任何子顺序处理,或者实际上并行处理;只要更高行的所有项都在后续行的项之前处理以保留依赖项。

答案 2 :(得分:1)

你的任务是一个定向图,(希望)没有周期。

我包含sourceswells(来源是不依赖的任务(没有入站边缘),井是没有任务解锁的任务(没有出站边缘))。

一个简单的解决方案是根据其有用性优先处理您的任务(让我们称之为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

意思是你将首先用E开始,然后是B和C(如果可能的话),然后是D和F

答案 3 :(得分:1)

首先生成任务的拓扑排序。检查此阶段的周期。此后,您可以通过查看最大的反链来利用并行性。粗略地说,这些是任务集,它们的元素之间没有依赖关系。

从理论角度来看,this paper涵盖了该主题。

答案 4 :(得分:0)

不考虑问题的串行/并行方面,此代码至少可以确定整个串行解决方案:

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

如果更新循环以检查完全满足的依赖关系以遍历整个列表并执行/删除不再具有任何依赖关系的任务,那么这也应该允许您利用完成并行的任务。