Как профилировать несколько подпроцессов с помощью Python multiprocessing и Memory profiler?

у меня есть утилита, которая порождает несколько рабочих с помощью Python multiprocessing модуль, и я хотел бы иметь возможность отслеживать их использование памяти через отличный memory_profiler утилита, которая делает все, что я хочу, - в частности, выборка использования памяти с течением времени и построение конечного результата (Меня не волнует профилирование строчной памяти для этого вопроса).

чтобы настроить этот вопрос, я создал более простую версию скрипт, который имеет рабочую функцию, которая выделяет память, подобную пример передана в 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

учитывая последовательную рабочую нагрузку 4 работников следующим образом:

if __name__ == '__main__':
    worker(5, 5, X6)
    worker(5, 2, X7)
    worker(5, 5, X6)
    worker(5, 2, X7)

под управлением mprof исполняемый файл для профилирования моего скрипта занимает 70 секунд, когда каждый работник запускается один за другим. Скрипт, работает следующим образом:

$ mprof run python myscript.py

производит следующее использование памяти график:

Sequential Memory Generating Workers

эти рабочие идут параллельно с multiprocessing означает, что сценарий завершится так же медленно, как самый медленный рабочий (25 секунд). Этот сценарий выглядит следующим образом:

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]

профайлер памяти действительно работает, или, по крайней мере, нет ошибок при использовании mprof но результаты немного странные:

enter image description here

быстрый взгляд на монитор активности показывает, что на самом деле есть 6 процессов Python, один для mprof для python myscript.py и затем по одному для каждого рабочего подпроцесса. Оказывается, что mprof измеряет только использование памяти для

1 ответов


на сегодняшний день в библиотеку профилировщика памяти добавлена новая функция, которая делает именно это. Если вам нужна эта функциональность, сначала обновите memory_profiler следующим образом:

$ pip install -U memory_profiler 

Это должно установить v0.44 выпуск профилировщика памяти. Чтобы проверить, что это так, используйте команду help в действии run:

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 флаг, то вы хорошо идти!

затем вы можете запустить ваш скрипт следует:

$ mprof run -M python myscript.py
$ mprof plot 

и вы должны получить фигуру, которая выглядит так:

mprof tracking individual child proccesses

обратите внимание, что если вы используете --include-children флаг также, основная память процесса будет общим использованием памяти всех детей и main, что также является полезным сюжетом.