为了测试一些安全软件,我需要能够在Windows中创建一个大的(可配置的)新进程(而不是线程!),非常快,让它们存在一段(可配置的)时间,然后彻底终止。这些过程根本不应该做任何事情 - 只存在指定的持续时间。
最终,我希望能够运行类似的东西:
C:\> python process_generate.py --processes=150 --duration=2500
可以非常快速地创建150个新进程,使它们在2500毫秒内保持活动状态,然后尽快终止它们。
作为起点,我跑了
from multiprocessing import Process
import os
def f():
pass
if __name__ == '__main__':
import datetime
count = 0
startime = datetime.datetime.now()
while True:
p = Process(target=f)
p.start()
p.terminate()
count += 1
if count % 1000 == 0:
now = datetime.datetime.now()
print "Started & stopped d processes in %s seconds" % (count, str(now-starttime))
发现我可以在笔记本电脑上创建和终止大约70个进程/秒串行,创建的进程会立即终止。约70个过程/秒速率持续约一小时。
当我将代码更改为
时from multiprocessing import Process
import os
import time
def f_sleep():
time.sleep(1)
if __name__ == '__main__':
import datetime
starttime = datetime.datetime.now()
processes = []
PROCESS_COUNT = 100
for i in xrange(PROCESS_COUNT):
p = Process(target=f_sleep)
processes.append(p)
p.start()
for i in xrange(PROCESS_COUNT):
processes[i].terminate()
now = datetime.datetime.now()
print "Started/stopped %d processes in %s seconds" % (len(processes), str(now-starttime))
并为PROCESS_COUNT尝试了不同的值,我预计它会比它更好地扩展。我得到了不同的PROCESS_COUNT值的以下结果:
这是不我所期望的 - 我希望能够以合理的线性方式扩展并行进程数,直到我遇到瓶颈,但我似乎几乎可以直接打击流程创建瓶颈。根据我运行的第一个代码,我肯定希望能够在达到流程创建瓶颈之前创建接近70个流程/秒的东西。
没有进入完整的规格,笔记本电脑运行完全修补的Windows XP,有4Gb RAM,否则是空闲的,是合理的新;我认为这不会很快成为瓶颈。
我在使用我的代码做了什么明显的错误,或者在12个月大的笔记本电脑上创建的XP / Python并行进程效率是否真的很低?
答案 0 :(得分:6)
嗯,Windows进程管理并不能很好地扩展。进程越多,将新的进程安排到调度中所需的时间就越长。
现在将其与其他操作系统内核进行比较,例如Linux,其中进程创建实际上是O(1)(常量时间),因为内核2.6.8(当引入了调度程序时)。
请注意,我不打算在这里向你推销Linux。我建议您在不同的操作系统上试用您的程序,以便自己查看。
答案 1 :(得分:3)
在对一系列不同场景进行分析和测试之后,我发现在Windows下生成和终止单个进程要快得多,而不是一次生成N个进程,终止所有N,然后重新启动N.
我的结论是,Windows保留了足够的资源,可以非常快速地一次启动1个进程,但还不足以启动&gt; 1个新的并发进程而没有相当大的延迟。正如其他人所说,Windows在启动新进程方面进展缓慢,但显然速度会随着系统上已经运行的并发进程数量而逐渐降级 - 开始一个进程非常快,但是当你开始多个进程时你遇到了问题。无论存在的CPU数量,机器的繁忙程度(通常在我的测试中<5%CPU),Windows是在物理服务器上运行还是在虚拟机上运行,有多少RAM可用(我测试的最多都是32Gb RAM,~24Gb免费),... - 它似乎只是Windows操作系统的限制。当我在相同的硬件上安装Linux时,限制消失了(根据Xavi的回复)我们能够非常快速地同时启动许多进程。
答案 2 :(得分:2)
我已经在Ubuntu 11.04 Dell Precision和4Gb RAM中测试了您的代码,结果如下:
Started/stopped 100 processes in 0:00:00.051061 seconds
Started/stopped 150 processes in 0:00:00.094802 seconds
Started/stopped 200 processes in 0:00:00.153671 seconds
Started/stopped 300 processes in 0:00:00.351072 seconds
Started/stopped 400 processes in 0:00:00.651631 seconds
Started/stopped 470 processes in 0:00:01.009148 seconds
Started/stopped 1000 processes in 0:00:02.532036 seconds
Started/stopped 10000 processes in 0:00:29.677061 seconds
每次执行时至少有10%的可变性具有相同数量的进程,希望这是有用的,在一秒钟内我的计算机用您的代码执行了近500个进程。
答案 3 :(得分:2)
如果我没记错,与Linux相反,Windows从未被设计为快速启动许多进程。这不是设计师认为你会做的事情 - 而在Linux上,有inetd
之类的东西,它是一个足够普遍的操作模型来保证优化 - 因此,流程创建就像地狱一样优化。
答案 4 :(得分:0)
我想说,在Linux中,创建许多Python进程也存在困难。经过500次运行p.start()后,它变得非常慢。
有时我需要创建数千个长时间工作的流程。
在上面的示例中,在一个时刻内没有PROCESS_COUNT个活动进程的数量,因为它们在1秒后开始完成工作。因此,如果在2秒内创建1000个进程,则超过一半的进程一直完成,直到创建过程结束。
from multiprocessing import Process
def sample():
sleep(13)
start = time()
for i in range(1500):
p = Process(target=sample)
p.daemon = True
p.start()
end = time()
print end - start
我尝试使用SUSE ENTERPRISE的140核服务器和使用Ubuntu的笔记本电脑 - 动态是相同的(服务器结果):
500 processes start - 1.36 s
1000 processes start - 9.7 s
1500 processes start - 18.4 s
2000 processes start - 24.3 s
3000 processes start - 43.3 s
因为fork之前的这个调用。每个新的子进程需要更长的时间
def _cleanup():
# check for processes which have finished
for p in list(_current_process._children):
if p._popen.poll() is not None:
_current_process._children.discard(p)
我记得,如果进程有manager.Value并且稍微重一点 - 它需要10 GB的RAM并且启动时间会更长。