[英]Can Python task scheduler Luigi detect indirect dependencies?
简洁版本:
Python中是否有一个任务调度程序可以执行gmake的工作? 特别是,我需要一个任务调度程序来递归地解决依赖关系。 我调查了Luigi,但它似乎只能解决直接依赖关系。
长版:
我正在尝试构建一个以预定义顺序处理大量数据文件的工作流,以后的任务可能直接取决于一些更艰巨的任务的输出,但是,这些输出的正确性甚至取决于更艰巨的任务。
例如,让我们考虑如下的依赖关系图:
A <-B <-C
当我从任务C请求结果时,Luigi将自动安排B,然后由于B取决于A,因此它将安排A。因此,最终的运行顺序将是[A,B,C]。 每个任务都会创建一个官方输出文件,作为成功执行的标志。 第一次运行就可以了。
现在,假设我在任务A的输入数据中犯了一个错误。显然,我需要重新运行整个链。 但是,仅从A中删除输出文件将不起作用。 因为Luigi看到了B和C的输出,并得出结论,任务C的要求已得到满足,因此不需要运行。 我必须从所有依赖于A的任务中删除输出文件,以便它们可以再次运行。 在简单的情况下,我必须删除A,B和C中的所有输出文件,以便Luigi能够检测到对A所做的更改。
这是一个非常不方便的功能。 如果我有数十个或数百个彼此之间具有相当复杂的依赖关系的任务,那么当需要重新运行其中一个任务时,很难说出哪些任务受到了影响。 对于任务调度程序并具有解决依赖关系的能力,我希望Luigi能够像GNU-Make一样工作,其中递归检查依赖关系,并且在更改最深的源文件之一时将重建最终目标。
我想知道是否有人可以提供有关此问题的建议。 我是否缺少Luigi的一些关键功能? 还有其他充当gmake的任务计划程序吗? 我对基于Python的软件包特别感兴趣,并希望它们支持Windows。
非常感谢!
似乎可以通过覆盖完成任务的完整方法来实现。 您必须将其一直应用到依赖图中。
def complete(self):
outputs = self.flatten(self.output())
if not all(map(lambda output: output.exists(), outputs)):
return False
for task in self.flatten(self.requires()):
if not task.complete():
for output in outputs:
if output.exists():
output.remove()
return False
return True
确实,这很不方便,并且d6tflow检查所有上游依赖项的完整性,而不仅仅是TaskC输出的存在。 如果重置TaskA,则TaskC也将不完整并自动重新运行。
# reset TaskA => makes TaskC incomplete
TaskA().invalidate()
d6tflow.preview(TaskC()) # all tasks pending
有关更多详细信息,请参见下面的完整示例和d6tflow docs 。
import d6tflow
import pandas as pd
class TaskA(d6tflow.tasks.TaskCachePandas): # save dataframe in memory
def run(self):
self.save(pd.DataFrame({'a':range(10)})) # quickly save dataframe
class TaskB(d6tflow.tasks.TaskCachePandas):
def requires(self):
return TaskA() # define dependency
def run(self):
df = self.input().load() # quickly load required data
df = df*2
self.save(df)
class TaskC(d6tflow.tasks.TaskCachePandas):
def requires(self):
return TaskB()
def run(self):
df = self.input().load()
df = df*2
self.save(df)
# Check task dependencies and their execution status
d6tflow.preview(TaskC())
'''
└─--[TaskC-{} (PENDING)]
└─--[TaskB-{} (PENDING)]
└─--[TaskA-{} (PENDING)]
'''
# Execute the model training task including dependencies
d6tflow.run(TaskC())
'''
===== Luigi Execution Summary =====
Scheduled 3 tasks of which:
* 3 ran successfully:
- 1 TaskA()
- 1 TaskB()
- 1 TaskC()
'''
# all tasks complete
d6tflow.preview(TaskC())
'''
└─--[TaskC-{} (COMPLETE)]
└─--[TaskB-{} (COMPLETE)]
└─--[TaskA-{} (COMPLETE)]
'''
# reset TaskA => makes TaskC incomplete
TaskA().invalidate()
d6tflow.preview(TaskC())
'''
└─--[TaskC-{} (PENDING)]
└─--[TaskB-{} (PENDING)]
└─--[TaskA-{} (PENDING)]
'''
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.