Python:分支工作流/管道的现有解决方案?

时间:2012-03-09 17:02:54

标签: python workflow pipeline

在我的应用程序中,我实现了由5个不同的“处理单元”组成的非常粗略的工作流程。目前的代码结构如下:

def run(self, result_first_step=None, result_second_step=None):

    config = read_workflow_config("config.ini")

    if config.first_step:
        result_first_step = run_process_1()

    if config.second_step and result_first_step is not None:
        result_second_step = run_process_2(result_first_step)
    else:
        raise Exception("Missing required data")

    if config.third_step:
        result_third_step = run_process_3(result_first_step, result_second_step)
    else:
        result_third_step = None

    collect_results(result_first_step, result_second_step, result_third_step)

等等。代码可以工作,但它很难维护并且非常脆弱(处理比这个简化的例子复杂得多)。所以,我一直在考虑采用另一种策略,即通过以下方式制定适当的工作流程:

  • 短路:我不能为启动过程或两种不同类型的数据提供数据。在后一种情况下,工作流程短路并跳过一些处理
  • 常见对象:所有单位均可使用的配置
  • 条件:根据配置,可能会跳过某些位

是否有可用于执行这些工作流程的Python库,还是应该自行编写?我一直在尝试使用pyutilib.workflow但它不能正常支持一个常见的配置对象,而不是将它传递给所有工作者(繁琐)。

注意:这适用于库/命令行应用程序,因此基于Web的工作流程解决方案不合适。

2 个答案:

答案 0 :(得分:0)

您可以将run方法变为生成器;

def run(self)
  result_first_step = run_process_1()
  yield result_first_step
  result_second_step = run_process_2(result_first_step)
  yield result_second_step
  result_third_step = run_process_3(result_first_step, result_second_step)
  collect_results(result_first_step, result_second_step, result_third_step)

答案 1 :(得分:0)

Python中的管道方法有很多种, 从半页到...... 这是主要的想法: 在顶部,将所有步骤定义放在dict中;
然后流水线(例如“C A T”)执行步骤C,A,T。

class Pipelinesimple:
    """p = Pipelinesimple( funcdict );  p.run( "C A T" ) = C(X) | A | T

    funcdict = dict( A = Afunc, B = Bfunc ... Z = Zfunc )
    pipeline = Pipelinesimple( funcdict )
    cat = pipeline.run( "C A T", X )  # C(X) | A | T, i.e. T( A( C(X) ))
    dog = pipeline.run( "D O G", X, **kw )  # D(X, **kw) | O(**kw) | G(**kw)
    """

def __init__( self, funcdict ):
    self.funcdict = funcdict  # funcs or functors of X

def run( self, steps, X, **commonargs ):
    """ steps "C A T" or ["C", "A", "T"]
        all funcs( X, **commonargs )
    """

    if isinstance( steps, basestring ):
        steps = steps.split()  # "C A T" -> ["C", "A", "T"]
    for step in steps:
        func = self.funcdict(step)
        # if X is None: ...
        X = func( X, **commonargs )
    return X

接下来,有几种方法可以提供不同的参数 到不同的步骤。

一种方法是解析多行字符串,例如

""" C  ca=5  cb=6 ...
    A  aa=1 ...
    T  ...
"""

另一个是获取函数/函数名称/参数序列的列表,如

pipeline.run( ["C", dict(ca=5, cb=6), lambda ..., "T", dict(ta=3) ])

第三种方式是将“A__aa B__ba ......”分开 sklearn.pipeline.Pipeline。 确实。 (这适用于机器学习,但您可以复制管道部件。)

每一项都有相当明确的优点和缺点。

  

一大群有才华的人可以拿出十几个原型   解决问题[管道]的速度非常快   但是将十几个减少到两个或三个需要永远。

无论你采取哪种方式, 提供一种记录运行所有参数的方法。

另见:
FilterPype
nipype