有些任务从文件中读取数据,进行一些处理并写入文件。这些任务将根据依赖性进行调度。此外,任务可以并行运行,因此需要优化算法以串行运行并尽可能并行运行相关任务。
例如:
所以运行这个的一种方法是运行 1、2、4并联。接下来是 3。
另一种方式可能是 运行 1,然后并行运行 2、3 和 4。
另一个可以串行运行 1 和 3,并行运行 2 和 4。
有什么想法吗?
让每个任务(例如
A,B,...
)成为有向无环图中的节点,并根据您的1,2,...
定义节点之间的弧。
然后您可以对图表进行拓扑排序(或使用基于搜索的方法,如BFS)。在您的示例中, C<-A->B->D
和
E->F
因此,
A
和
E
的深度为 0,需要首先运行。然后您可以并行运行
F
、
B
和
C
,然后运行
D
。另外,看看
PERT。
更新:你怎么知道B
是否比
F
具有更高的优先级?这是用于查找排序的拓扑排序背后的直觉。
它首先找到根(无传入边)节点(因为 DAG 中必须存在)。就您而言,那就是
A
和
E
。这就解决了需要完成的第一轮工作。接下来,需要完成根节点(
B
、
C
和
F
)的子节点。这可以通过查询图表轻松获得。然后重复该过程,直到找不到节点(作业)(完成)。
此 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
输出中一行上的项目可以按任何子顺序进行处理,或者实际上可以并行处理;只要上一行的所有项目都在下一行的项目之前处理,以保留依赖性。
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
从理论角度来看,
本文涵盖了该主题。
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
如果您更新检查已完全满足的依赖项的循环以循环整个列表并同时执行/删除不再具有任何依赖项的任务,那么这也应该允许您利用完成任务的优势并行。