2015-09-11 7 views
0

У меня есть код, который использует Pool из модуля multiprocessing Python. Производительность - это не то, что я ожидаю, и хотел бы прокомментировать код, чтобы выяснить, что происходит. Проблема, с которой я столкнулась, заключается в том, что выход профилирования перезаписывается для каждой работы, и я не могу накопить разумное количество статистических данных.профилирование пула многопроцессорности python

Например, с:

import multiprocessing as mp 
import cProfile 
import time 
import random 

def work(i): 
    x = random.random() 
    time.sleep(x) 
    return (i,x) 

def work_(args): 
    out = [None] 
    cProfile.runctx('out[0] = work(args)', globals(), locals(), 
        'profile-%s.out' % mp.current_process().name) 
    return out[0] 

pool = mp.Pool(10) 

for i in pool.imap_unordered(work_, range(100)): 
    print(i) 

Я только получить статистику по «последней» работу, которая не может быть наиболее вычислительно требуют один. Я полагаю, что мне нужно хранить статистику где-то, а затем записывать их только тогда, когда пул очищается.

ответ

0

по docs вы можете использовать атрибут pid, чтобы получить уникальное имя для каждого выходного файла

cProfile.runctx('out[0] = work(args)', globals(), locals(), 
       'profile-%s-%s.out' % (mp.current_process().pid, datetime.now().isoformat())) 
+0

проблема заключается в том, что 'runctx' перезаписывает выход на каждом вызове, поскольку он выполняется несколько раз, вы получите только«последний» работа для каждого процесса - собирать сообщение полурабочее решение –

+0

ah ok - все написано за каждый процесс - почему бы просто не добавить временную метку? – scytale

+0

, потому что у меня есть * много * рабочих мест, выполняемых в реальной жизни, и я не хочу, чтобы миллионы небольших файлов профиля –

1

Мое решение включает в себя проведение на объект профиля дольше и только писать его на «конце» , Присоединение к пулевому пулу описано better elsewhere, но включает в себя использование объекта Finalize для выполнения явно dump_stats() в соответствующее время.

Это также позволяет мне убрать неудобный батут work_, необходимый с runctx, которым я пользовался раньше.

import multiprocessing as mp 
import cProfile 
import time 
import random 

def work(i): 
    # enable profiling (refers to the global object below) 
    prof.enable() 
    x = random.random() 
    time.sleep(x) 
    # disable so we don't profile the Pool 
    prof.disable() 
    return (i,x) 

# Initialise a good profile object and make sure it gets written during Pool teardown 
def _poolinit(): 
    global prof 
    prof = cProfile.Profile() 
    def fin(): 
     prof.dump_stats('profile-%s.out' % mp.current_process().pid) 

    mp.util.Finalize(None, fin, exitpriority=1) 

# create our pool 
pool = mp.Pool(10, _poolinit) 

for i in pool.imap_unordered(work, range(100)): 
    print(i) 

Загрузка вывод показывает, что множественные вызовы действительно были записаны:

> p = pstats.Stats("profile-ForkPoolWorker-5.out") 
> p.sort_stats("time").print_stats(10) 
Fri Sep 11 12:11:58 2015 profile-ForkPoolWorker-5.out 

     30 function calls in 4.684 seconds 

    Ordered by: internal time 

    ncalls tottime percall cumtime percall filename:lineno(function) 
     10 4.684 0.468 4.684 0.468 {built-in method sleep} 
     10 0.000 0.000 0.000 0.000 {method 'random' of '_random.Random' objects} 
     10 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects} 
Смежные вопросы