【发布时间】:2011-10-13 17:15:11
【问题描述】:
我有一个正在运行的命令行程序,我将文本作为参数输入:
somecommand.exe 它会运行一段时间(通常是一个小时到几个小时的好几分之一),然后将结果写入多个文本文件。我正在尝试编写一个脚本来同时启动其中的几个,使用多核机器上的所有内核。在其他操作系统上我会分叉,但这并没有在 Windows 的许多脚本语言中实现。 Python 的多处理似乎可以解决问题,所以我想我会尝试一下,尽管我根本不知道 python。我希望有人能告诉我我做错了什么。 我编写了一个脚本(如下),我指向一个目录,如果找到可执行文件和输入文件,然后使用 pool.map 和一个 n 池启动它们,并使用调用来启动它们。我看到的是,最初(启动第一组 n 个进程)看起来不错,100% 使用 n 个内核。但随后我看到进程处于空闲状态,不使用或仅使用百分之几的 CPU。那里总是有 n 个进程,但它们做的并不多。当他们去写入输出数据文件时似乎会发生这种情况,一旦开始,一切都会陷入困境,整体核心利用率范围从百分之几到偶尔达到 50-60% 的峰值,但永远不会接近 100%。 如果我可以附上它(编辑:我不能,至少现在不能)这里是进程的运行时间图。较低的曲线是当我打开 n 个命令提示符并手动保持 n 个进程一次运行时,很容易将计算机保持在 100% 附近。 (这条线是规则的,在 32 个不同的进程中从接近 0 小时慢慢增加到 0.7 小时,改变一个参数。)上面的线是这个脚本的某个版本的结果——运行时间平均增加了大约 0.2 小时,并且是更不可预测,就像我在底线中添加了 0.2 + 一个随机数。 这是剧情的链接:
Run time plot 编辑:现在我想我可以添加情节了。
我做错了什么?from multiprocessing import Pool, cpu_count, Lock
from subprocess import call
import glob, time, os, shlex, sys
import random
def launchCmd(s):
mypid = os.getpid()
try:
retcode = call(s, shell=True)
if retcode < 0:
print >>sys.stderr, "Child was terminated by signal", -retcode
else:
print >>sys.stderr, "Child returned", retcode
except OSError, e:
print >>sys.stderr, "Execution failed:", e
if __name__ == '__main__':
# ******************************************************************
# change this to the path you have the executable and input files in
mypath = 'E:\\foo\\test\\'
# ******************************************************************
startpath = os.getcwd()
os.chdir(mypath)
# find list of input files
flist = glob.glob('*_tin.txt')
elist = glob.glob('*.exe')
# this will not act as expected if there's more than one .exe file in that directory!
ex = elist[0] + ' < '
print
print 'START'
print 'Path: ', mypath
print 'Using the executable: ', ex
nin = len(flist)
print 'Found ',nin,' input files.'
print '-----'
clist = [ex + s for s in flist]
cores = cpu_count()
print 'CPU count ', cores
print '-----'
# ******************************************************
# change this to the number of processes you want to run
nproc = cores -1
# ******************************************************
pool = Pool(processes=nproc, maxtasksperchild=1) # start nproc worker processes
# mychunk = int(nin/nproc) # this didn't help
# list.reverse(clist) # neither did this, or randomizing the list
pool.map(launchCmd, clist) # launch processes
os.chdir(startpath) # return to original working directory
print 'Done'
【问题讨论】:
-
你看起来真的很清楚自己在做什么;对于自称是新手的人来说,这看起来像是很好的 Python。问题一:CPU空闲时,硬盘是不是超级忙?从理论上讲,如果您的进程产生大量输出,则在等待磁盘写入所有内容时,这些进程可能大部分时间都是空闲的。如果由于某种原因缓存不起作用,则尤其如此。
-
当 CPU 使用率下降时(这发生在第一个进程开始写入其输出时),磁盘活动似乎(如资源监视器报告的那样)出现峰值,然后保持在 100% 附近,直到好在所有过程完成之后。磁盘队列也达到了 50。我很好奇为什么会出现这种情况,但当我从多个命令行手动执行相同的命令时却不是——看起来确实有些东西被共享了(很糟糕)。
-
我应该补充一点:我不在乎这些进程以什么顺序完成。在示例中,我现在正在尝试最短的先运行。随机化或颠倒顺序可能会有所帮助,但影响不大。
标签: python windows multiprocessing pool