Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/362.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python “我如何实施?”;“弱”;NetworkX的边? 出身背景_Python_Networkx_Topological Sort - Fatal编程技术网

Python “我如何实施?”;“弱”;NetworkX的边? 出身背景

Python “我如何实施?”;“弱”;NetworkX的边? 出身背景,python,networkx,topological-sort,Python,Networkx,Topological Sort,我正在编写一个Python模块来收集和安排夜间自动更新的任务,并提供交互执行单个任务的选项。(夜间更新无条件运行所有任务。) 其中一些单独的任务依赖于另一个任务的执行才能正常运行:例如,如果任务A已安排(自动或手动),但任务B未安排,则必须将任务B添加到A之前的计划中。我将这些称为强依赖性,因为它们在必要时“拉入”新任务 其他任务依赖于另一个任务的输出,但如果该任务未计划,也可以对旧输出进行操作;e、 g.如果任务C已计划,但任务D未计划,则不添加D,并且C在旧数据上运行。我把它们称为弱依赖项

我正在编写一个Python模块来收集和安排夜间自动更新的任务,并提供交互执行单个任务的选项。(夜间更新无条件运行所有任务。)

  • 其中一些单独的任务依赖于另一个任务的执行才能正常运行:例如,如果任务A已安排(自动或手动),但任务B未安排,则必须将任务B添加到A之前的计划中。我将这些称为强依赖性,因为它们在必要时“拉入”新任务

  • 其他任务依赖于另一个任务的输出,但如果该任务未计划,也可以对旧输出进行操作;e、 g.如果任务C已计划,但任务D未计划,则不添加D,并且C在旧数据上运行。我把它们称为弱依赖项,因为它们“太弱”了,无法对计划进行更改

我已经成功地使用
nx.DiGraph
来构建依赖关系,并使用
nx.topological\u sort
来生成最终任务计划(以请求的任务作为起始节点),实现了强依赖关系。然而,我不确定如何实现弱依赖性,因为
拓扑排序
似乎总是添加由任何边连接的节点。我甚至尝试将边缘的权重设置为0,但没有成功

实施 编辑:这里是我当前实现的一个粗略示例

#tasklib.py
task_graph=nx.DiGraph()
def运行(启动_任务):
全局任务图
对于glob.glob('modules/*.py')中的modname:
__导入(os.path.splitext(modname)[0]。替换('/','))
任务队列=nx.拓扑排序(任务图、启动任务)
#在此处删除弱链接的任务
对于任务队列中的t:
任务图.节点[t]['func']()
def任务(func):
任务\图形。添加\节点(func.\名称\ func,func=func)
返回函数
def dependens(*args):#强依赖性
def添加部门(职能):
对于参数中的dep:
任务图。添加边(函数名,dep)
返回函数
返回add_deps
(*args)后的def:#弱依赖性
def添加部门(职能):
对于参数中的dep:
任务图。添加边(函数名,dep,弱=真)
返回函数
返回add_deps
#模块/mytasks.py
从tasklib导入任务,取决于,在
@任务
def process_data():
#做一些冗长的处理
@任务
@取决于('过程\数据')
def process_more_data():
#对上述输出进行更多处理
@任务
@之后('process_data')
def生成_报告():
#生成有关已处理数据的报告
在这里,
process\u more\u data
需要从
process\u data
获得最新的输出,然后才能继续作业,因此它使用了强依赖性。另一方面,
generate_report
如果自己运行,则可以使用旧数据执行此操作,但如果
process_data
也已安排,则在即将生成新结果时,就旧数据生成报告是没有意义的;它不应该运行到之后

根据@BrenBarn的建议,我可能会尝试向
run
添加一个附加步骤,从
task\u队列中删除弱链接的任务,除非它们也存在于
start\u tasks

问题 我的问题归结为:只有当两个节点都在起始节点集中时,我才能生成参与排序的边吗?如果是,怎么做?如果没有,是否有其他方法或库可以实现此效果

出于我自己的目的,我曾考虑编写一个具有此功能的精简网络库,但我希望有更好的方法

额外学分
除了上面提到的,我还想支持“post dependencies,”其中一个任务意味着一个依赖性任务在它后面运行-但我担心这超出了仅仅拓扑排序的范围。

一种方法是构建一个依赖关系图,其中包含
a
B
之间的有向边,当且仅当
a
强烈依赖
B
,或者
A
弱地依赖于
B
B
强烈地依赖于其他任务

这里有一些代码就是这样做的。在这个例子中,我们将考虑六个任务,<代码> a <代码> >代码> f<代码>:

import networkx as nx

deps = nx.DiGraph()
deps.add_nodes_from("abcdef")
deps.add_edges_from([("a","b"), ("c","a"), ("e","c")], is_strong=True)
deps.add_edges_from([("f","c"), ("d","c")], is_strong=False)
我们可以将其理解为
a
b
等的强要求,
f
c
的弱要求。用户将选择要运行的任务
a
c
。由于任务
a
运行,我们需要
c
在它之前运行,因此也需要
e
c
之前运行。任务
d
没有强依赖性,但它是
c
的弱依赖性。因此,我们希望按照以下顺序运行任务:
d、e、c、a

首先,我们将提取由丢弃所有弱边而产生的子图。我们将在此图中查看每个计划任务的祖先:这是我们需要运行的依赖项集。然后我们只取这些节点所产生的完全依赖图的子图。此图上的拓扑排序产生我们所需的解决方案

代码如下:

def construct_task_graph(deps, tasks):
    required = set(tasks)
    strong_subgraph = extract_strong_subgraph(deps)
    for task in tasks:
        ancestors = nx.ancestors(strong_subgraph, task)
        required.update(ancestors)

    return nx.subgraph(deps, required)

def extract_strong_subgraph(deps):
    strong_deps = nx.DiGraph()
    strong_deps.add_nodes_from(deps)

    strong_edges = (e for e in deps.edges_iter(data=True) if e[2]["is_strong"])
    strong_deps.add_edges_from(strong_edges)

    return strong_deps
请注意,
construct\u task\u graph
有点低效:任务可能是在早期迭代中处理的任务的祖先,产生重复的需求。这些都是由集合抛出的,但更有效的方法是实现类似DFS的东西

无论如何,我们得到:

>>> task_graph = construct_task_graph(deps, ["a", "d"])
>>> task_graph.nodes()
['a', 'c', 'e', 'd']
>>> task_graph.edges()
[('c', 'a'), ('e', 'c'), ('d', 'c')]
最重要的是:

>>> nx.topological_sort(task_graph)
['d', 'e', 'c', 'a']

我不会区分这些依赖关系,只是从一个任务返回以前没有运行过的旧数据,如果从一个弱依赖性任务链接过来的话。如果我理解正确,那么在创建图的过程中这样做似乎更有意义。也就是说,当添加任务C时,如果任务D不在图中,则不添加它;如果是,则向其添加边。别这样