我有一个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]
...
无论如何,关于问题的原因。我将这个脚本提交给一个Grid Engine系统来打破这个巨大的参数空间扫描到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似乎不会改变。