我有一个 python 脚本,它使用多处理的 pool.map( ... ) 并行运行大量计算。这些计算中的每一个都包含为 fortran 程序设置输入的 python 脚本,使用 subprocess.popen( ... , stdin=PIPE, stdout=PIPE, stderr=PIPE ) 运行程序,将输入转储到它并读取输出。然后脚本解析输出,获取所需的数字,然后再次执行下一次运行。
def main():
#Read a configuration file
#do initial setup
pool = multiprocessing.Pool(processes=maxProc)
runner = CalcRunner( things that are the same for each run )
runNumsAndChis = pool.map( runner, xrange(startRunNum, endRunNum))
#dump the data that makes it past a cut to disk
class CalcRunner(object):
def __init__(self, stuff):
#setup member variables
def __call__(self, runNumber):
#get parameters for this run
params = self.getParams(runNum)
inFileLines = []
#write the lines of the new input file to a list
makeInputFile(inFileLines, ... )
process = subprocess.Popen(cmdString, bufsize=0, stdin=subprocess.PIPE, ... )
output = proc.communicate( "".join(inFileLines) )
#get the needed numbers from stdout
chi2 = getChiSq(output[0])
return [runNumber, chi2]
...
无论如何,关于问题的原因。我将此脚本提交给网格引擎系统,以将这个巨大的参数空间扫描分解为 1000、12 核(我选择 12,因为大多数网格是 12 核)、任务。当单个任务在单个 12 核机器上运行时,机器大约 1/3 的时间用于系统工作,而另外 2/3 的时间用于用户计算,大概是设置 ECIS 的输入(前面提到的 FORTRAN代码),运行 ECIS,并解析 ECIS 的输出。然而,有时 5 个任务被发送到 64 核机器以利用其 60 个核。在那台机器上,40% 的时间花在系统工作上,1-2% 时间花在用户工作上。
首先,所有系统调用来自哪里?我尝试编写一个程序版本,该版本每个单独的线程运行一次 ECIS 并不断向它输送新的输入,它在系统中花费了更多时间(并且总体上更慢),所以这似乎不是由于所有进程创建和删除。其次,如何减少花费在系统调用上的时间?
猜测一下,打开一个进程一次并继续向它发送输入会比较慢,因为我必须关闭 gfortran 的输出缓冲才能从进程中获取任何内容,其他任何工作都没有(除了修改 fortran 代码......这不是发生)。
我开发这个的家庭测试机器上的操作系统是 Fedora 14。网格机器上的操作系统是 Red Hat 的最新版本。
我尝试过使用 bufsize,将其设置为 -1(系统默认值)、0(无缓冲)、1(逐行)和 64Kb,这似乎不会改变事情。