Как я могу профилировать память многопоточной программы в Python?
есть ли способ профилировать память многопоточной программы в Python?
для профилирования цп я использую cProfile для создания отдельной статистики профилировщика для каждого потока и последующего их объединения. Однако я не мог найти способ сделать это с помощью профилировщиков памяти. Я использую бесформенный.
есть ли способ объединить статистику в heapy, как cProfile? Или какие другие профилировщики памяти вы бы предложили, что более подходит для этой задачи.
соответствующий вопрос было предложено профилировать использование ЦП по многопоточной программе:как я могу профилировать многопоточную программу в Python?
также еще один вопрос относительно профилировщика памяти:профилировщик памяти Python
4 ответов
Если вы счастливы профилировать объекты, а не сырую память, вы можете использовать gc.get_objects()
функция, поэтому вам не нужен пользовательский метакласс. В более поздних версиях Python, sys.getsizeof()
также позволит вам попытаться выяснить, сколько базовой памяти используется этими объектами.
есть способы получить valgrind для профилирования памяти программ python:http://www.python.org/dev/faq/#can-i-run-valgrind-against-python
Ok. То, что я искал, похоже, не существует. Итак, я нашел решение-обходной путь для этой проблемы.
вместо профилирования памяти я буду профилировать объекты. Таким образом, я смогу увидеть, сколько объектов существует в определенное время в программе. Чтобы достичь своей цели, я использовал метаклассы с минимальной модификацией уже существующего кода.
следующий метакласс добавляет очень простую подпрограмму в __init__
и __del__
функции класс. Подпрограмма для __init__
увеличивает количество объектов с этим именем класса на единицу и __del__
уменьшается на один.
class ObjectProfilerMeta(type):
#Just set metaclass of a class to ObjectProfilerMeta to profile object
def __new__(cls, name, bases, attrs):
if name.startswith('None'):
return None
if "__init__" in attrs:
attrs["__init__"]=incAndCall(name,attrs["__init__"])
else:
attrs["__init__"]=incAndCall(name,dummyFunction)
if "__del__" in attrs:
attrs["__del__"]=decAndCall(name,attrs["__del__"])
else:
attrs["__del__"]=decAndCall(name,dummyFunction)
return super(ObjectProfilerMeta, cls).__new__(cls, name, bases, attrs)
def __init__(self, name, bases, attrs):
super(ObjectProfilerMeta, self).__init__(name, bases, attrs)
def __add__(self, other):
class AutoClass(self, other):
pass
return AutoClass
функции incAndCall и decAndCall используют глобальную переменную модуля, в котором они существуют.
counter={}
def incAndCall(name,func):
if name not in counter:
counter[name]=0
def f(*args,**kwargs):
counter[name]+=1
func(*args,**kwargs)
return f
def decAndCall(name,func):
if name not in counter:
counter[name]=0
def f(*args,**kwargs):
counter[name]-=1
func(*args,**kwargs)
return f
def dummyFunction(*args,**kwargs):
pass
dummyFunction - это просто очень простой обходной путь. Я уверен, что есть гораздо лучшие способы сделать это.
наконец, всякий раз, когда вы хотите увидеть количество объектов, которые существуют, вам просто нужно посмотреть на счетчик словарь. Пример:
>>> class A:
__metaclass__=ObjectProfilerMeta
def __init__(self):
pass
>>> class B:
__metaclass__=ObjectProfilerMeta
>>> l=[]
>>> for i in range(117):
l.append(A())
>>> for i in range(18):
l.append(B())
>>> counter
{'A': 117, 'B': 18}
>>> l.pop(15)
<__main__.A object at 0x01210CB0>
>>> counter
{'A': 116, 'B': 18}
>>> l=[]
>>> counter
{'A': 0, 'B': 0}
Я надеюсь, это поможет вам. Этого было достаточно для моего случая.
Я использовал Yappi, С которым у меня был успех для нескольких специальных многопоточных случаев. У него отличная документация, поэтому у вас не должно быть слишком много проблем с ее настройкой.
для конкретного профилирования памяти, проверьте бесформенный. Будьте осторожны, он может создать некоторые из самых больших файлов журнала, которые вы когда-либо видели!