从python脚本在集群上加载环境模块

从python脚本在集群上加载环境模块,python,slurm,Python,Slurm,我需要向服务器提交一个python作业。当它运行时,我需要在运行时加载和卸载模块,因为它调用多个程序,每个程序都有不同的依赖关系,即gcc与intel之间的冲突 以前有人问过这个问题,但在这种情况下,答案对我来说并不适用 我试过使用以下方法 import subprocess as sub cmd = 'module load intel/2016.4' p = sub.Popen(cmd, shell=True, stderr = sub.STDOUT, stdout = sub.PIPE

我需要向服务器提交一个python作业。当它运行时,我需要在运行时加载和卸载模块,因为它调用多个程序,每个程序都有不同的依赖关系,即gcc与intel之间的冲突

以前有人问过这个问题,但在这种情况下,答案对我来说并不适用

我试过使用以下方法

import subprocess as sub
cmd = 'module load intel/2016.4'
p = sub.Popen(cmd, shell=True, stderr = sub.STDOUT, stdout = sub.PIPE).communicate()[0] 
print(p.decode()) # this simply outputs to screen
输出显示模块已切换

Lmod is automatically replacing "gcc/5.4.0" with "intel/2016.4".

Due to MODULEPATH changes, the following have been reloaded:
  1) openmpi/2.1.1
但是,当我从终端执行“模块列表”时,模块尚未切换<代码>gcc/5.4.0仍在加载中。此外,需要
英特尔/2016.4
的程序也无法运行。例如,稍后我希望能够使用需要
intel/2016.4
的gromacs版本,但失败了


我有点困惑,因为我认为我可以通过Popen使用bash命令,“模块加载”是bash命令。我不想写一个bash脚本来实现这一点,我的脚本中有很多其他的东西用python比bash更方便。

我最近遇到了这个问题。解决此问题的一种简单方法是在所需命令之前包含依赖项,并用分号分隔它们

cmd = 'module load intel/2016.4; "gromacs command"'
p = sub.Popen(cmd, shell=True, stderr = sub.STDOUT, stdout = sub.PIPE).communicate()[0]
其中“gromacs命令”表示您通常会调用的gromacs。
intel/2016.4
如果在运行脚本后进行检查,则不会在模块列表中显示为已加载,但gromacs将使用
intel/2016.4
从python脚本内部运行,这正是您想要的。

大多数环境模块实现都有一个非常方便的python init脚本。对于
lmod
,它位于
$lmod\u DIR/./init
中,名为
env\u modules\u python.py
。所以你可以这样做:

$ export PYTHONPATH=${PYTHONPATH}:$LMOD_DIR/../init
$ python
Python 2.7.5 (default, Jul 13 2018, 13:06:57)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-28)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from env_modules_python import module
从那里,您可以直接在Python中运行任何“module”命令

>>> module('list')

Currently Loaded Modules:

[...]
  3) StdEnv                                             (H)
  4) GCCcore/6.4.0                                      (H)
  5) binutils/2.28-GCCcore-6.4.0                        (H)
[...]
它将修改Python脚本的环境,并且该环境将被传播到子shell

>>> import os
>>> os.system("which icc")
which: no icc in (/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin)
256
>>> module("load intel")
>>> os.system("which icc")
/opt/[...]/icc/2017.4.196-GCC-6.4.0-2.28/compilers_and_libraries_2017.4.196/linux/bin/intel64/icc
0
它与Popen的工作原理相同:

>>> import subprocess as sub
>>> cmd='which icc'
>>> p = sub.Popen(cmd, shell=True, stderr = sub.STDOUT, stdout = sub.PIPE).communicate()[0]
>>> print(p.decode())
/opt/[...]icc/2017.4.196-GCC-6.4.0-2.28/compilers_and_libraries_2017.4.196/linux/bin/intel64/icc

当执行
Popen
调用时,Python生成一个新的子shell,在该子shell中运行module命令,最后关闭该子shell,丢失刚才所做的更改。这就是为什么完成后您无法看到更改的原因。这就是为什么一个新命令在同一个子shell中启动时可以工作的原因。所以,如果给定模块被多次调用,是否每次都需要在命令中加载它?