【问题标题】:Submitting jobs using python使用 python 提交作业
【发布时间】:2013-10-26 06:05:57
【问题描述】:

我正在尝试使用 python 脚本在我们研究所的集群中提交一份工作。

 compile_cmd = 'ifort -openmp ran_numbers.f90 ' + fname \
                  + ' ompscmf.f90 -o scmf.o'
 subprocess.Popen(compile_cmd, shell=True)

 Popen('qsub launcher',shell=True)

问题是,系统此时挂起。上面的脚本有什么明显的错误吗?代码中提到的所有文件都在该目录中可用(我已经交叉检查过)。 qsub 是用于向我们的集群提交作业的命令。 fname 是我在此过程中创建的文件的名称。

【问题讨论】:

  • 为什么不使用django-celery
  • subprocess.Popen(['qsub', 'launcher']) 可能会更好。 shell=True 如果你真的需要的话。
  • @WayneWerner 我很难弄清楚Popen('qsub launcher')Popen('qsub', 'launcher') 之间的区别。你能解释一下吗?
  • 这不是两个单独的参数,而是一个列表。有时Popen 在确定应该如何拆分参数时遇到问题,至少在我的经验中是这样。

标签: python jobs


【解决方案1】:

你有没有得到任何错误。因为您似乎错过了第二次 Popen 的“subprocess.”。

【讨论】:

  • 已经从子进程导入,所以不需要显式调用。不,我没有任何具体的错误。
  • 哦,好的。该部分未包含在您提供的 sn-p 中。我不知道问题是什么,因为我以前从未使用过 qsub。
  • 对不起。我应该给的。
【解决方案2】:

我有一个脚本,用于使用 qsub 向我们的集群提交多个作业。 qsub 通常以表单形式提交作业

qsub [qsub options] job

在我的工作中,作业通常是一个 bash (.sh) 或 python 脚本 (.py),它实际调用要在每个节点上运行的程序或代码。如果我想提交一个名为“test_job.sh”的作业,并且具有最长的挂壁时间,我会这样做

qsub -l walltime=72:00:00 test_job.sh

相当于下面的python代码

from subprocess import call

qsub_call = "qsub -l walltime=72:00:00 %s"
call(qsub_call % "test_job.sh", shell=True)

或者,如果您有一个看起来像这样的 bash 脚本会怎样

#!/bin/bash

filename="your_filename_here"
ifort -openmp ran_numbers.f90 $filename ompscmf.f90 -o scmf.o

然后通过qsub job.sh提交这个?


编辑:老实说,最佳作业排队方案因集群而异。简化作业提交脚本的一种简单方法是找出每个节点上可用的 CPU 数量。一些较新的排队系统允许您提交许多单 CPU 作业,它们会在尽可能少的节点上一起提交这些作业;但是,一些较旧的集群不会这样做,并且不赞成提交许多单独的作业。

假设集群中的每个节点都有 8 个 CPU。你可以写你的脚本像

#!/bin/bash
#PBS -l nodes=1;ppn=8

for ((i=0; i<8; i++))
do
    ./myjob.sh filename_${i} &
done
wait

这将做的是一次在一个节点上提交 8 个作业(&amp; 表示在后台执行)并等待所有 8 个作业完成。这对于每个节点有很多 CPU 的集群可能是最佳的(例如,我使用的一个集群每个节点有 48 个 CPU)。

或者,如果提交许多单核作业是最佳的,并且您上面的提交代码不起作用,您可以使用 python 生成 bash 脚本以传递给 qsub。

#!/usr/bin/env python
import os
from subprocess import call

bash_lines = ['#!/bin/bash\n', '#PBS -l nodes=1;ppn=1\n']
bash_name = 'myjob_%i.sh'
job_call = 'ifort -openmp ran_numbers.f90 %s ompscmf.f90 -o scmf.o &\n'
qsub_call = 'qsub myjob_%i.sh'

filenames = [os.path.join(root, f) for root, _, files in os.walk(directory)
                                   for f in files if f.endswith('.txt')]
for i, filename in enumerate(filenames):
    with open(bash_name%i, 'w') as bash_file:
        bash_file.writelines(bash_lines + [job_call%filename, 'wait\n'])
    call(qsub_call%i, shell=True)

【讨论】:

  • Popencall 更通用,所以两者都应该工作。但是,我发现call 更易于使用我需要立即完成的简单命令,因为call does block。但是,我仍然不确定您为什么使用 python 提交作业。您是否遍历了许多 fnames 并提交了许多单独的作业?对于大多数集群和排队系统来说,这似乎不是最优的,可能有更好的方法。
  • 是的,我正在迭代许多 fnames 并提交许多单独的工作。我不知道任何最佳方法。能否请您提供这些方面的指导方针?
  • 我在 OP 中添加了一些额外的 cmets。您可能需要联系运行集群的任何人以获取一些指南和最佳实践。
  • 您可以使用for ((i=0; i&lt;${PBS_NUM_PPN}; i++)),而不是在for循环中硬编码8个内核。
猜你喜欢
  • 2019-08-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多