【问题标题】:How can I profile memory of multithread program in Python?如何在 Python 中分析多线程程序的内存?
【发布时间】:2011-06-15 12:15:54
【问题描述】:

有没有办法在 Python 中分析多线程程序的内存?

对于 CPU 分析,我使用 cProfile 为每个线程创建单独的分析器统计信息,然后将它们组合起来。但是,我找不到使用内存分析器执行此操作的方法。我正在使用 heapy。

有没有办法像 cProfile 一样将统计数据组合成堆?或者您会建议哪些其他内存分析器更适合此任务。

针对多线程程序的 CPU 使用情况分析提出了一个相关问题:How can I profile a multithread program in Python?

还有一个关于内存分析器的问题:Python memory profiler

【问题讨论】:

  • 您不喜欢其他问题中的解决方案的哪些方面?
  • @Falmarri,我正在寻找一个“内存”分析器。第一个主要是 CPU 分析器。第二个仅适用于单个线程。
  • 线程的主要特点是它们共享内存(与进程相反)。您希望如何分析共享所有相同内存的线程的不同内存统计信息?
  • @scoffey heapy,内存分析器,不会将所有线程分析为一个。它只分析它运行的线程的内存使用情况。我正在寻找一种方法来分析整个过程的记忆。同样的想法也适用于 CPU 分析器,即 cProfile 模块。但是,有一种方法可以将不同线程的配置文件统计信息与 cProfile 结合起来,我在上面给出的链接中对此进行了说明。

标签: python multithreading profiling memory-profiling


【解决方案1】:

如果您乐于分析对象而不是原始内存,则可以使用gc.get_objects() 函数,这样您就不需要自定义元类。在最近的 Python 版本中,sys.getsizeof() 还可以让您了解这些对象使用了多少底层内存。

【讨论】:

  • 这很棒。比我的方法干净得多。
【解决方案2】:

有一些方法可以让 valgrind 分析 python 程序的内存:http://www.python.org/dev/faq/#can-i-run-valgrind-against-python

【讨论】:

  • 以前从未听说过 valgrind;一定会检查出来的。
  • @funktku 这是用于分析内存使用情况和检测内存泄漏的标准工具。
【解决方案3】:

好的。我正在寻找的东西似乎并不存在。所以,我找到了一个解决方案——解决这个问题的方法。

我将分析对象,而不是分析内存。这样,我将能够查看程序中特定时间存在多少对象。为了实现我的目标,我利用元类对现有代码进行了最少的修改。

下面的元类为类的__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}

我希望这对你有帮助。对我来说已经足够了。

【讨论】:

    【解决方案4】:

    我使用了Yappi,在一些特殊的多线程案例中我已经成功地使用了它。它有很棒的文档,所以设置它应该不会有太多麻烦。

    有关内存特定分析,请查看Heapy。请注意,它可能会创建一些您所见过的最大的日志文件!

    【讨论】:

    • 不幸的是,我知道这两个分析器,并提供了指向专门讨论 Yappi 和 Heapy 的相关问题的链接。问题是,yappi 不分析内存,而 heapy 只分析主线程的内存使用情况(更准确地说是调用它的线程)。
    • @KushalP。我试过 Yaapi,我认为它不能给我的逐行执行时间。我错过了什么吗?
    猜你喜欢
    • 2010-10-13
    • 2014-10-27
    • 2014-06-21
    • 2011-05-21
    • 1970-01-01
    • 2016-02-23
    • 1970-01-01
    • 2010-09-05
    相关资源
    最近更新 更多