如何使用Python多处理和内存分析器分析多个子流程?
我有一个实用程序,它使用Python模块生成多个工作人员,我希望能够通过优秀的实用程序跟踪他们的内存使用情况,该实用程序可以完成我想要的一切—特别是随时间采样内存使用情况并绘制最终结果(我不关心这个问题的逐行内存分析) 为了设置这个问题,我创建了一个更简单的脚本版本,它有一个worker函数,分配的内存与如何使用Python多处理和内存分析器分析多个子流程?,python,python-multiprocessing,memory-profiling,Python,Python Multiprocessing,Memory Profiling,我有一个实用程序,它使用Python模块生成多个工作人员,我希望能够通过优秀的实用程序跟踪他们的内存使用情况,该实用程序可以完成我想要的一切—特别是随时间采样内存使用情况并绘制最终结果(我不关心这个问题的逐行内存分析) 为了设置这个问题,我创建了一个更简单的脚本版本,它有一个worker函数,分配的内存与memory\u profiler库中给出的类似。工作人员如下: import time X6 = 10 ** 6 X7 = 10 ** 7 def worker(num, wait, am
memory\u profiler
库中给出的类似。工作人员如下:
import time
X6 = 10 ** 6
X7 = 10 ** 7
def worker(num, wait, amt=X6):
"""
A function that allocates memory over time.
"""
frame = []
for idx in range(num):
frame.extend([1] * amt)
time.sleep(wait)
del frame
import multiprocessing as mp
if __name__ == '__main__':
pool = mp.Pool(processes=4)
tasks = [
pool.apply_async(worker, args) for args in
[(5, 5, X6), (5, 2, X7), (5, 5, X6), (5, 2, X7)]
]
results = [p.get() for p in tasks]
$ pip install -U memory_profiler
$ mprof run -M python myscript.py
$ mprof plot
考虑到连续4名工人的工作量,如下所示:
if __name__ == '__main__':
worker(5, 5, X6)
worker(5, 2, X7)
worker(5, 5, X6)
worker(5, 2, X7)
$ mprof run python myscript.py
运行mprof
可执行文件来评测我的脚本需要70秒,让每个工作进程一个接一个地运行。脚本将按如下方式运行:
if __name__ == '__main__':
worker(5, 5, X6)
worker(5, 2, X7)
worker(5, 5, X6)
worker(5, 2, X7)
$ mprof run python myscript.py
生成以下内存使用率图:
让这些worker与多处理并行运行
意味着脚本将以最慢的worker(25秒)的速度完成。该脚本如下:
import time
X6 = 10 ** 6
X7 = 10 ** 7
def worker(num, wait, amt=X6):
"""
A function that allocates memory over time.
"""
frame = []
for idx in range(num):
frame.extend([1] * amt)
time.sleep(wait)
del frame
import multiprocessing as mp
if __name__ == '__main__':
pool = mp.Pool(processes=4)
tasks = [
pool.apply_async(worker, args) for args in
[(5, 5, X6), (5, 2, X7), (5, 5, X6), (5, 2, X7)]
]
results = [p.get() for p in tasks]
$ pip install -U memory_profiler
$ mprof run -M python myscript.py
$ mprof plot
内存分析器确实可以工作,或者至少在使用mprof
时没有错误,但结果有点奇怪:
快速查看Activity Monitor可以发现实际上有6个Python进程,一个用于mprof
,一个用于Python myscript.py
,然后每个辅助进程一个。似乎mprof
只是测量python myscript.py
进程的内存使用情况
memory\u profiler
库是高度可定制的,我相信我应该能够捕获每个进程的内存,并可能使用库本身将它们写入单独的日志文件。我只是不确定从何处开始,也不知道如何达到这种定制水平
编辑
在阅读了mprof
脚本之后,我确实发现了-C
标志,它总结了所有子(分叉)进程的内存使用情况。这将产生一个(大大改进的)图表,如下所示:
import time
X6 = 10 ** 6
X7 = 10 ** 7
def worker(num, wait, amt=X6):
"""
A function that allocates memory over time.
"""
frame = []
for idx in range(num):
frame.extend([1] * amt)
time.sleep(wait)
del frame
import multiprocessing as mp
if __name__ == '__main__':
pool = mp.Pool(processes=4)
tasks = [
pool.apply_async(worker, args) for args in
[(5, 5, X6), (5, 2, X7), (5, 5, X6), (5, 2, X7)]
]
results = [p.get() for p in tasks]
$ pip install -U memory_profiler
$ mprof run -M python myscript.py
$ mprof plot
但我要寻找的是每个单独子进程随时间的内存使用情况,这样我就可以在同一个图上绘制所有工作进程(和主进程)。我的想法是将每个子进程
内存使用情况
写入一个不同的日志文件,然后将其可视化 从今天起,内存探查器库中添加了一项新功能,可以实现这一点。如果需要此功能,请首先按如下方式更新memory_profiler:
import time
X6 = 10 ** 6
X7 = 10 ** 7
def worker(num, wait, amt=X6):
"""
A function that allocates memory over time.
"""
frame = []
for idx in range(num):
frame.extend([1] * amt)
time.sleep(wait)
del frame
import multiprocessing as mp
if __name__ == '__main__':
pool = mp.Pool(processes=4)
tasks = [
pool.apply_async(worker, args) for args in
[(5, 5, X6), (5, 2, X7), (5, 5, X6), (5, 2, X7)]
]
results = [p.get() for p in tasks]
$ pip install -U memory_profiler
$ mprof run -M python myscript.py
$ mprof plot
这应该安装v0.44版本的内存探查器。要检查是否存在这种情况,请对运行操作使用help命令:
mprof run --help
Usage: mprof run [options]
Options:
--version show program's version number and exit
-h, --help show this help message and exit
--python Activates extra features when the profiling executable
is a Python program (currently: function
timestamping.)
--nopython Disables extra features when the profiled executable
is a Python program (currently: function
timestamping.)
-T INTERVAL, --interval=INTERVAL
Sampling period (in seconds), defaults to 0.1
-C, --include-children
Monitors forked processes as well (sum up all process
memory)
-M, --multiprocess Monitors forked processes creating individual plots
for each child
如果您看到-M
标志,那么您就可以开始了
然后,您可以按如下方式运行脚本:
import time
X6 = 10 ** 6
X7 = 10 ** 7
def worker(num, wait, amt=X6):
"""
A function that allocates memory over time.
"""
frame = []
for idx in range(num):
frame.extend([1] * amt)
time.sleep(wait)
del frame
import multiprocessing as mp
if __name__ == '__main__':
pool = mp.Pool(processes=4)
tasks = [
pool.apply_async(worker, args) for args in
[(5, 5, X6), (5, 2, X7), (5, 5, X6), (5, 2, X7)]
]
results = [p.get() for p in tasks]
$ pip install -U memory_profiler
$ mprof run -M python myscript.py
$ mprof plot
你应该得到这样一个数字:
请注意,如果同时使用
--include children
标志,则主进程内存将是所有子进程和主进程的总内存使用量,这也是一个有用的绘图 如果有人感兴趣,这个问题将在GitHub上与开发者讨论。特别感谢@fabian pedregosa帮助实现这一点!在这种模式下启用时间戳和@profile
装饰器怎么样?可能吗?我不知道你说的启用时间戳是什么意思?我认为这应该可以通过@profile
装饰器实现,它使用相同的参数。不幸的是,我无法让它工作。请看一下是否有一种方法可以为子进程命名child-n
不是真正的解释:)