dflow入门6——Subpath_slices

为了梳理学习dflow时遇到的知识点,我决定开这一个系列记录自己的学习过程。当然了,最好是去看 文档
本文,我们将讨论dflow的一个feature,Subpath_slices,并在最后写一个应用。

阅读原测试文件

test_subpath_slices.py 在源码example目录下
文件开始定义了两个OP

class Prepare(OP):
    def __init__(self):
        pass

    @classmethod
    def get_input_sign(cls):
        return OPIOSign({
        })

    @classmethod
    def get_output_sign(cls):
        return OPIOSign({
            'foo': Artifact(List[str], archive=None)
        })

    @OP.exec_sign_check
    def execute(
            self,
            op_in: OPIO,
    ) -> OPIO:
        with open("foo1.txt", "w") as f:
            f.write("foo1")
        with open("foo2.txt", "w") as f:
            f.write("foo2")
        op_out = OPIO({
            'foo': ["foo1.txt", "foo2.txt"]
        })
        return op_out


class Hello(OP):
    def __init__(self):
        pass

    @classmethod
    def get_input_sign(cls):
        return OPIOSign({
            'foo': Artifact(str)
        })

    @classmethod
    def get_output_sign(cls):
        return OPIOSign()

    @OP.exec_sign_check
    def execute(
            self,
            op_in: OPIO,
    ) -> OPIO:
        with open(op_in["foo"], "r") as f:
            print(f.read())
        return OPIO()

第一个OP没有输入,输出是一个list格式的artifact,值得注意的是,这里有一个label是archive=None
点进注释可以看到,archive=None 指不对文件进行压缩
在这里插入图片描述
第二个OP是读入单个文件,然后对该文件进行一些操作,没有输出
最后,我们来看套的壳

    wf = Workflow("subpath-slices")
    prepare = Step("prepare",
                   PythonOPTemplate(Prepare, image="python:3.8"))
    wf.add(prepare)

    hello = Step("hello",
                 PythonOPTemplate(Hello, image="python:3.8",
                                  slices=Slices(sub_path=True,
                                                input_artifact=["foo"]
                                                )
                                  ),
                 artifacts={"foo": prepare.outputs.artifacts["foo"]})
    wf.add(hello)
    wf.submit()
    while wf.query_status() in ["Pending", "Running"]:
        time.sleep(1)

    assert(wf.query_status() == "Succeeded")

首先是在wf里加入了prepare,然后把
prepare的输出传给了hello的输入,并在Slice里指定了要切割的对象,sub_path=True就可以了!!

这相当于我以前代码里:

  1. 把这个文件夹传给第二步
  2. 在第二步里进入文件夹,然后 os.listdir('./') 获取该文件夹下的每个工作目录,再进入该目录完成工作!!

使用sub_path之后就是:

  1. 把文件夹传给第二步
  2. 第二步使用slice之后,只关心工作目录里的业务操作即可。

应用案例

第一个OP实现工作目录的搭建

class BuildWithSub(OP):
    def __init__(self):
        pass

    @classmethod
    def get_input_sign(cls):
        return OPIOSign({
            'in_workbase': Artifact(Path),
        })

    @classmethod
    def get_output_sign(cls):
        return OPIOSign({
            'out_workbase': Artifact(type=List[Path], archive=None),
        })

    @OP.exec_sign_check
    def execute(
            self,
            op_in: OPIO,
    ) -> OPIO:
        name = 'cooking'
        cwd_ = os.getcwd()
        dst = os.path.abspath(name)
        os.makedirs(dst, exist_ok=True)
        if os.path.isdir(os.path.join(op_in['in_workbase'], 'raw')):
            raw = os.path.abspath(os.path.join(op_in['in_workbase'], 'raw'))
        else:
            raw = os.path.abspath(op_in['in_workbase'])
        outs = []
        for a_file in os.listdir(raw):
            os.chdir(dst)
            a_file_name = os.path.splitext(a_file)[0]
            os.makedirs(a_file_name, exist_ok=True)
            shutil.copy(src=os.path.join(raw, a_file), dst=os.path.join(a_file_name, a_file))
            outs.append(Path(os.path.join(name, a_file_name)))
        os.chdir(cwd_)
        op_out = OPIO({
            "out_workbase": outs,
        })
        return op_out

第二个OP实现:进入工作目录,执行命令

class simpleExe(OP):
    def __init__(self):
        pass

    @classmethod
    def get_input_sign(cls):
        return OPIOSign({
            'workbase': Artifact(Path),
            'cmd_list': List[str],
            'out_list': List[str],
            'in_fmt': str,
            'log_file': str,
        })

    @classmethod
    def get_output_sign(cls):
        return OPIOSign({
            'outs': Artifact(type=List[Path]),
        })

    @OP.exec_sign_check
    def execute(
            self,
            op_in: OPIO,
    ) -> OPIO:
        cwd_ = os.getcwd()
        os.chdir(op_in['workbase'])
        cmd_list = op_in['cmd_list']
        outs = []

        if op_in['in_fmt'] == 'null':
            cmd_list.append(os.listdir('./')[0])
        else:
            for a_file in os.listdir('./'):
                if a_file.endswith(op_in['in_fmt']):
                    cmd_list.append(a_file)
                    break

        log_file = op_in['log_file']
        cmd_list.append(f'>>{log_file}')
        # time.sleep(60)
        os.system(' '.join(cmd_list))

        for an_output in op_in['out_list']:
            if os.path.exists(an_output):
                outs.append(Path(os.path.join(op_in['workbase'], an_output)))
        os.chdir(cwd_)
        op_out = OPIO({
            "outs": outs,
        })
        return op_out

外边的壳是:

    a_build = Step(name='build',
                   template=PythonOPTemplate(BuildWithSub, image="franklalalala/py_autorefiner"),
                   artifacts={'in_workbase': src_dir}
                   )

    an_exe = Step(name='exe',
                  template=PythonOPTemplate(simpleExe,
                                            image="franklalalala/py_autorefiner",
                                            slices=Slices(sub_path=True,
                                                          input_artifact=["workbase"]
                                                          )
                                            ),
                  artifacts={'workbase': a_build.outputs.artifacts['out_workbase']},
                  parameters={'cmd_list': ['xtb', '--opt tight'],
                              'out_list':['xtbopt.xyz', 'xtbopt.log'],
                              'in_fmt': None, 'log_file': None
                              },
                  executor=dispatcher_executor,
                  )

需要注意的是:

  1. 第一个OP的输出是一个list的形式,且achive=None
  2. 第二个OP download 时,名字为exe的step有10个(batch_size个)
    在这里插入图片描述
  3. 和普通的slice模式相比,每个工作目录只有一个输入文件,逻辑确实清晰很多,但每个工作目录都要搭配一个dflow的包(及其他所有要上传的包)。考虑到这一点,还是之前的实现更加轻便。1000以下的高通量计算可以接受类似的冗余。


上传一个16K的workbase需要搭配1.3M的package
du -h --max-depth=1 查询当前文件夹目录下,各文件大小

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值