Python 编写和运行DAG任务最干净的方法是什么?

Python 编写和运行DAG任务最干净的方法是什么?,python,concurrency,directed-acyclic-graphs,Python,Concurrency,Directed Acyclic Graphs,我想编写并运行一个有向无环图(DAG),其中有几个任务以串行或并行方式运行。理想的情况是: def task1(): # ... def task2(): # ... 图=序列([ 任务1, 任务2, 平行的([ 任务3, 任务4 ]), 任务5 ] graph.run() 它将运行1->2->(3和4并发)->5。任务需要访问全局范围以存储结果、写入日志和访问命令行参数 我的用例是编写部署脚本。并行任务是IO绑定的:通常在远程服务器上等待完成一个步骤 我研究了线程、asyncio和Airfl

我想编写并运行一个有向无环图(DAG),其中有几个任务以串行或并行方式运行。理想的情况是:

def task1():
# ...
def task2():
# ...
图=序列([
任务1,
任务2,
平行的([
任务3,
任务4
]),
任务5
]
graph.run()
它将运行1->2->(3和4并发)->5。任务需要访问全局范围以存储结果、写入日志和访问命令行参数

我的用例是编写部署脚本。并行任务是IO绑定的:通常在远程服务器上等待完成一个步骤


我研究了线程、asyncio和Airflow,但没有找到任何简单的库,可以在没有样板代码的情况下遍历和控制图形的执行。是否存在类似的库?

这里是一个概念验证的快速实现。它可以像这样使用:

graph = sequence(
            lambda: print(1),
            lambda: print(2),
            parallel(
                lambda: print(3),
                lambda: print(4),
                sequence(
                    lambda: print(5),
                    lambda: print(6))),
             lambda: print(7)

graph()

1
2
3
5
6
4
7
sequence
生成一个函数来包装
for
循环,而
parallel
生成一个函数来包装线程池的使用:

from typing import Callable
from multiprocessing.pool import ThreadPool

Task = Callable[[], None]

_pool: ThreadPool = ThreadPool()

def sequence(*tasks: Task) -> Task:
    def run():
        for task in tasks:
            task()

    return run  # Returning "run" to be used as a task by other "sequence" and "parallel" calls

def parallel(*tasks: Task) -> Task:
    def run():
        _pool.map(lambda f: f(), tasks)  # Delegate to a pool used for IO tasks

    return run
sequence
parallel
的每次调用都会返回一个新的“任务”(一个不带参数且不返回任何内容的函数)。然后,对
sequence
parallel
的其他外部调用可以调用该任务

有关
线程池的注意事项

  • 虽然这确实使用线程池来执行
    并行
    ,但由于GIL的原因,这仍然一次只执行一件事情。这意味着
    并行
    对于CPU限制的任务基本上是无用的

  • 我没有指定池应该从多少线程开始。我认为它默认为您可以使用的内核数。如果您想要更多,可以使用
    ThreadPool
    的第一个参数指定要从多少线程开始

  • 为了简单起见,我并没有清理
    线程池

  • 尽管
    ThreadPool
    多处理
    的一部分,但令人困惑的是,它使用的是线程而不是进程


编写将任务排队的
序列
并行
函数可能相当简单。
序列
基本上只是一个
for
循环,而
并行
只是将任务交给
多处理.Pool.map
。这些任务是IO绑定的还是CPU绑定的?如果对于后者,您将需要进入多处理兔子洞,并可能下载该模块的替代版本。内置的
多处理
具有严重的限制。IO绑定(等待远程服务器完成部署步骤)考虑到用例,可能不会,但您是否会有大量的
并行对象(如运行时每秒数百个)?可同时运行的任务总数是否会超过1000个?此问题的解决方案,但在java中:@Carcigenicate当您说应该清理线程池时,您指的是什么?@haidahaida线程池在理想情况下需要手动关闭。完成后,手动调用池上的
shutdown
.