所谓管道,我们指的是把任务链接在一起,形成复杂的管道。
1 简单连接
此时,您知道如何在工作流脚本中包含多个任务。如果您在有关变量的部分中注意,您甚至知道如何将一个任务的输出连接到下一个任务的输入。使您能够构建线性或简单分支合并任意长度的工作流,具有单个或多输入多输出任务之间的连接。
2 切换迭代逻辑
除了这些基本的连接功能之外,您有时还需要能够在交替路径之间切换,并对数据集进行迭代,无论是串联的还是并行的。为此,我们需要更多的代码,但别担心.你不用写任何东西!我们将利用WDL语法的各个方面和一些方便的内置特性,这些特性使添加这种逻辑非常容易。在WDL中,我们最喜欢的这种类型的特性是分散收集并行性,当您需要将相同的命令应用于可以作为独立单元处理的数据子集时,这是加快执行速度的好方法。
3 代码重用的效率
最后,你会发现你经常需要在不同的环境中做类似的事情。与其将相关代码复制到多个地方–这会产生更多的代码以进行维护和更新–相反,您可以很灵活地重用代码。如果你的问题涉及到以不同的方式运行相同的工具,或者大量导入工作流,你可以通过任务别名来解决这个问题。<-抱歉,后者还没有完全实现,但它在开发路线图上。
管道选项
线性链
在工作流中将任务链接到一起的最简单方法是线性链,将一个任务的输出提供给下一个任务的输入,如下所示:
这很容易做到,因为WDL允许我们使用task_name.output_variable
语法引用另一个任务的call
语句中的任何任务的输出(适当地在任务的output
块中声明)。这里,我们简单地在对stepB的调用中指定我们希望它使用stepA。输出’作为输入变量in
的值,这与stepC的规则相同。
call stepB { input: in=stepA.out }
call stepC { input: in=stepB.out }
这依赖于称为分层命名的原则,该原则 使我们能够通过组件的上下级关系来识别组件。
多输入/多输出
将输出连接到输入的能力(在线性链接中描述)( 依赖于分层命名),该功能依赖于分层命名,使您可以将产生多个输出并接受多个输入的工具链接在一起,并准确指定将哪个输出馈送到哪个输入。
由于stepB的输出名称不同,我们可以指定下一步输入字段中的每个输出的确切位置。
call stepC { input: in1=stepB.out1, in2=stepB.out2 }
分支合并
将输出连接到线性链接和多输入/输出(依赖于分层命名)中描述的输入的能力可以进一步扩展,从而将任务的输出定向到单独的路径,对它们执行一些操作,然后将分支路径合并到一起。
在这里,您可以看到stepA同时提供给stepB****和stepC产生不同的输出,然后我们一起输入stepD.
call stepB { input: in=stepA.out }
call stepC { input: in=stepA.out }
call stepD { input: in1=stepC.out, in2=stepB.out }
条件语句(IF/Else)
条件条件已从Cromwell版本24开始实施。
有时候,在执行管道时,有些步骤是您想要运行的,而不是其他时候。这可能意味着在两个路径之间切换(例如,在Modea中运行一个工具,在modeB中运行一个工具),或者跳过一个步骤(例如运行一个工具而不是运行一个工具)。在这种情况下,我们将使用条件性声明。
要在wdl中使用条件语句,可以编写一个标准if
声明:
if(shouldICallStepB){
call stepB {input: in=stepA.out}
}
这个if
语句可以显式控制,就像我们在上面的示例中使用布尔变量所做的那样。它还可以通过测试其他变量的值来隐式控制,这些变量除了是开关机制之外,还有它自己的用途。即:if(myVar>0) { call stepB }
WDL还没有的一件事是else
声明。现在,为了解决这个问题,我们写成一对if语句使用!
修饰符以获得原始变量的相反值,如下所示:
Boolean myBoolVar
if(myBoolVar) { call taskA }
if(!myBoolVar) { call taskB }
分散 - 聚集 并行性
并行是一种通过并行执行几个操作,而不是按顺序执行(即在启动下一个操作之前等待每个操作完成)来使程序更快地完成的一种方法。有关并行性的更详细介绍,请深入阅读。这里.
为此,我们使用scatter
函数的WDL标准库,它将产生可并行的作业,在数组中的每个输入上运行相同的任务,并将结果输出为数组。
Array[File] inputFiles
scatter (oneFile in inputFiles) {
call stepA { input: in=oneFile }
}
call stepB { input: files=stepA.out }
这里的魔力在于产生输出数组并将其传递到下一个任务,而无需您明确声明它是一个数组。即使stepA的输出基于其声明看起来像是单个文件,但只要stepA.out
在任何其他 call
语句中进行引用 ,WDL就足以知道您是指将所有并行化stepA作业的输出分组的数组。
换句话说,过程的 分散 部分是 显式的, 而 聚集 部分是 隐式的。
任务别名
当您需要在工作流程中多次调用任务时,可以使用任务别名。每次需要在工作流程中再次使用它时,复制粘贴任务的定义并更改名称将很繁琐。这种称为复制和粘贴编程的方法 非常简单,但从长远来看却很难维护。想象一下,您在一项任务中发现了一个错字-您需要在每个粘贴的任务中修复该错字!但是,使用WDL的内置任务别名功能,您可以调用相同的任务代码并为其分配别名。然后,遵循分层命名的原理,为了访问别名任务的输出,我们使用别名而不是原始任务名称。
要使用别名,我们使用语法 call taskName as aliasName
。
call stepA as firstSample { input: in=firstInput }
call stepA as secondSample { input: in=secondInput }
call stepB { input: in=firstSample.out }
call stepC { input: in=secondSample.out }