如何在Python中分析多线程程序的内存?

发布于 2024-10-13 20:04:24 字数 468 浏览 6 评论 0原文

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

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

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

有人提出了一个有关分析多线程程序上的 CPU 使用情况的相关问题:如何在Python中分析多线程程序?

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

Is there a way to profile memory of a multithread program in Python?

For CPU profiling, I am using the cProfile to create seperate profiler stats for each thread and later combine them. However, I couldn't find a way to do this with memory profilers. I am using heapy.

Is there a way to combine stats in heapy like the cProfile? Or what other memory profilers would you suggest that is more suitable for this task.

A related question was asked for profiling CPU usage over multi-thread program: How can I profile a multithread program in Python?

Also another question regarding the memory profiler: Python memory profiler

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

递刀给你 2024-10-20 20:04:24

如果您愿意分析对象而不是原始内存,则可以使用 gc。 get_objects() 函数,因此您不需要自定义元类。在较新的 Python 版本中,sys.getsizeof() 还可以让您尝试计算出这些对象使用了多少底层内存。

If you are happy to profile objects rather than raw memory, you can use the gc.get_objects() function so you don't need a custom metaclass. In more recent Python versions, sys.getsizeof() will also let you take a shot at figuring out how much underlying memory is in use by those objects.

扛刀软妹 2024-10-20 20:04:24

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

There are ways to get valgrind to profile memory of python programs: http://www.python.org/dev/faq/#can-i-run-valgrind-against-python

乄_柒ぐ汐 2024-10-20 20:04:24

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

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

以下元类向该类的 __init__ 和 __del__ 函数添加了一个非常简单的子例程。 __init__ 的子例程将具有该类名的对象数量增加 1,而 __del__ 减少 1。

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}

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

Ok. What I was exactly looking for does not seem to exist. So, I found a solution-a workaround for this problem.

Instead of profiling memory, I'll profile objects. This way, I'll be able to see how many objects exist at a specific time in the program. In order to achieve my goal, I made use of metaclasses with minimal modification to already existing code.

The following metaclass adds a very simple subroutine to __init__ and __del__ functions of the class. The subroutine for __init__ increases the number of objects with that class name by one and the __del__ decreases by one.

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

The incAndCall and decAndCall functions use use global variable of the module they exist.

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

The dummyFunction is just a very simple workaround. I am sure there are much better ways to do it.

Finally, whenever you want to see the number of objects that exist, you just need to look at the counter dictionary. An example;

>>> 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}

I hope this helps you. It was sufficient for my case.

ぇ气 2024-10-20 20:04:24

我使用过 Yappi,我已经成功地使用了一些特殊的多线程案例。它有很好的文档,因此您在设置它时不会遇到太多麻烦。

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

I've used Yappi, which I've had success with for a few special multi-threaded cases. It's got great documentation so you shouldn't have too much trouble setting it up.

For memory specific profiling, check out Heapy. Be warned, it may create some of the largest log files you've ever seen!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文