优化算法来调度具有依赖性的任务?

问题描述 投票:0回答:5

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

例如:

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

所以运行这个的一种方法是运行 1、2、4并联。接下来是 3。

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

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

有什么想法吗?

algorithm scheduled-tasks scheduling directed-acyclic-graphs
5个回答
17
投票

让每个任务(例如

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
具有更高的优先级?

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

它首先找到根(无传入边)节点(因为 DAG 中必须存在)。就您而言,那就是

A

E
。这就解决了需要完成的第一轮工作。接下来,需要完成根节点(
B
C
F
)的子节点。这可以通过查询图表轻松获得。然后重复该过程,直到找不到节点(作业)(完成)。


10
投票
给定项目及其依赖的项目之间的映射,拓扑排序会对项目进行排序,以便没有项目位于其依赖的项目之前。

此 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

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


2
投票
您的任务是一个有向图(希望)没有循环。

I 包含

sources

wells
(源是不依赖的任务(没有入站边缘),井是不解锁任何任务的任务(没有出站边缘))。

一个简单的解决方案是根据任务的有用性优先考虑任务(我们称之为

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


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

从理论角度来看,

本文涵盖了该主题。


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

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

© www.soinside.com 2019 - 2024. All rights reserved.