मैं पायथन में मेमोरी का उपयोग कैसे करूं?


230

मैंने हाल ही में एल्गोरिदम में दिलचस्पी ली है और एक भोली कार्यान्वयन लिखकर और फिर इसे विभिन्न तरीकों से अनुकूलित करके उनकी खोज शुरू कर दी है।

मैं प्रोफाइलिंग रनटाइम के लिए पहले से ही मानक पायथन मॉड्यूल से परिचित हूं (ज्यादातर चीजों के लिए जिसे मैं आईपीथॉन में टाइमिट मैजिक फंक्शन को पर्याप्त मान रहा हूं), लेकिन मैं मेमोरी उपयोग में भी दिलचस्पी रखता हूं, इसलिए मैं उन ट्रेडऑफ्स का भी पता लगा सकता हूं ( उदाहरण के लिए पहले से गणना किए गए मूल्यों की एक तालिका को कैशिंग करने की लागत बनाम उन्हें आवश्यकतानुसार पुनर्संयोजित करना)। क्या कोई मॉड्यूल है जो मेरे लिए दिए गए फ़ंक्शन के मेमोरी उपयोग को प्रोफ़ाइल करेगा?


जवाबों:


118

यह पहले से ही यहाँ उत्तर दिया गया है: पायथन मेमोरी प्रोफाइलर

मूल रूप से आप ऐसा कुछ करते हैं ( गप्पी-पीई से उद्धृत ):

>>> from guppy import hpy; h=hpy()
>>> h.heap()
Partition of a set of 48477 objects. Total size = 3265516 bytes.
 Index  Count   %     Size   % Cumulative  % Kind (class / dict of class)
     0  25773  53  1612820  49   1612820  49 str
     1  11699  24   483960  15   2096780  64 tuple
     2    174   0   241584   7   2338364  72 dict of module
     3   3478   7   222592   7   2560956  78 types.CodeType
     4   3296   7   184576   6   2745532  84 function
     5    401   1   175112   5   2920644  89 dict of class
     6    108   0    81888   3   3002532  92 dict (no owner)
     7    114   0    79632   2   3082164  94 dict of type
     8    117   0    51336   2   3133500  96 type
     9    667   1    24012   1   3157512  97 __builtin__.wrapper_descriptor
<76 more rows. Type e.g. '_.more' to view.>
>>> h.iso(1,[],{})
Partition of a set of 3 objects. Total size = 176 bytes.
 Index  Count   %     Size   % Cumulative  % Kind (class / dict of class)
     0      1  33      136  77       136  77 dict (no owner)
     1      1  33       28  16       164  93 list
     2      1  33       12   7       176 100 int
>>> x=[]
>>> h.iso(x).sp
 0: h.Root.i0_modules['__main__'].__dict__['x']
>>> 

6
आधिकारिक गप्पी प्रलेखन थोड़ा न्यूनतम है; अन्य संसाधनों के लिए इस उदाहरण और ढेर निबंध को देखें
टूटुज्जु

13
गुप्पी को अब बनाए रखा नहीं लगता है, इसलिए मेरा सुझाव है कि इस उत्तर को डाउनग्रेड किया जाए और इसके बजाय स्वीकार किए गए अन्य उत्तरों में से एक है।
रोबगिनेंस

1
@robguinness डाउनग्रेड करने से आपका मतलब है डाउन-वोटेड? यह उचित नहीं लगता क्योंकि यह एक समय में मूल्यवान था। मुझे लगता है कि यह बताते हुए शीर्ष पर एक संपादन अब एक्स कारण के लिए मान्य नहीं है और इसके बजाय उत्तर वाई या जेड को देखने के लिए है। मुझे लगता है कि कार्रवाई का यह पाठ्यक्रम अधिक उपयुक्त है।
विनयुनुच्स 2 यूनिक्स

1
यकीन है, यह भी काम करता है, लेकिन किसी भी तरह से यह अच्छा होगा यदि स्वीकृत और उच्चतम मतदान जवाब में एक समाधान शामिल है जो अभी भी काम करता है और बनाए रखा जाता है।
११:

92

पायथन 3.4 में एक नया मॉड्यूल शामिल है tracemalloc:। यह विस्तृत आँकड़े प्रदान करता है कि कौन सा कोड सबसे अधिक मेमोरी आवंटित कर रहा है। यहां एक उदाहरण है जो मेमोरी को आवंटित करने वाली शीर्ष तीन लाइनों को प्रदर्शित करता है।

from collections import Counter
import linecache
import os
import tracemalloc

def display_top(snapshot, key_type='lineno', limit=3):
    snapshot = snapshot.filter_traces((
        tracemalloc.Filter(False, "<frozen importlib._bootstrap>"),
        tracemalloc.Filter(False, "<unknown>"),
    ))
    top_stats = snapshot.statistics(key_type)

    print("Top %s lines" % limit)
    for index, stat in enumerate(top_stats[:limit], 1):
        frame = stat.traceback[0]
        # replace "/path/to/module/file.py" with "module/file.py"
        filename = os.sep.join(frame.filename.split(os.sep)[-2:])
        print("#%s: %s:%s: %.1f KiB"
              % (index, filename, frame.lineno, stat.size / 1024))
        line = linecache.getline(frame.filename, frame.lineno).strip()
        if line:
            print('    %s' % line)

    other = top_stats[limit:]
    if other:
        size = sum(stat.size for stat in other)
        print("%s other: %.1f KiB" % (len(other), size / 1024))
    total = sum(stat.size for stat in top_stats)
    print("Total allocated size: %.1f KiB" % (total / 1024))


tracemalloc.start()

counts = Counter()
fname = '/usr/share/dict/american-english'
with open(fname) as words:
    words = list(words)
    for word in words:
        prefix = word[:3]
        counts[prefix] += 1
print('Top prefixes:', counts.most_common(3))

snapshot = tracemalloc.take_snapshot()
display_top(snapshot)

और यहाँ परिणाम हैं:

Top prefixes: [('con', 1220), ('dis', 1002), ('pro', 809)]
Top 3 lines
#1: scratches/memory_test.py:37: 6527.1 KiB
    words = list(words)
#2: scratches/memory_test.py:39: 247.7 KiB
    prefix = word[:3]
#3: scratches/memory_test.py:40: 193.0 KiB
    counts[prefix] += 1
4 other: 4.3 KiB
Total allocated size: 6972.1 KiB

स्मृति रिसाव कब रिसाव नहीं है?

वह उदाहरण महान है जब मेमोरी अभी भी गणना के अंत में आयोजित की जा रही है, लेकिन कभी-कभी आपके पास कोड होता है जो बहुत सारी मेमोरी आवंटित करता है और फिर यह सब जारी करता है। यह तकनीकी रूप से एक मेमोरी लीक नहीं है, लेकिन यह अधिक मेमोरी का उपयोग कर रहा है जितना आपको लगता है कि इसे करना चाहिए। जब यह सब रिलीज़ हो जाता है तो आप मेमोरी के उपयोग को कैसे ट्रैक कर सकते हैं? यदि यह आपका कोड है, तो संभवतः स्नैपशॉट लेने के लिए कुछ डिबगिंग कोड जोड़ सकते हैं, जबकि यह चल रहा है। यदि नहीं, तो आप स्मृति उपयोग की निगरानी के लिए एक पृष्ठभूमि थ्रेड शुरू कर सकते हैं जबकि मुख्य धागा चलता है।

यहां पिछला उदाहरण है जहां कोड को सभी count_prefixes()फ़ंक्शन में स्थानांतरित कर दिया गया है । जब वह फ़ंक्शन वापस आता है, तो सभी मेमोरी रिलीज़ होती है। मैंने sleep()लंबे समय तक चलने वाली गणना को अनुकरण करने के लिए कुछ कॉल भी जोड़े ।

from collections import Counter
import linecache
import os
import tracemalloc
from time import sleep


def count_prefixes():
    sleep(2)  # Start up time.
    counts = Counter()
    fname = '/usr/share/dict/american-english'
    with open(fname) as words:
        words = list(words)
        for word in words:
            prefix = word[:3]
            counts[prefix] += 1
            sleep(0.0001)
    most_common = counts.most_common(3)
    sleep(3)  # Shut down time.
    return most_common


def main():
    tracemalloc.start()

    most_common = count_prefixes()
    print('Top prefixes:', most_common)

    snapshot = tracemalloc.take_snapshot()
    display_top(snapshot)


def display_top(snapshot, key_type='lineno', limit=3):
    snapshot = snapshot.filter_traces((
        tracemalloc.Filter(False, "<frozen importlib._bootstrap>"),
        tracemalloc.Filter(False, "<unknown>"),
    ))
    top_stats = snapshot.statistics(key_type)

    print("Top %s lines" % limit)
    for index, stat in enumerate(top_stats[:limit], 1):
        frame = stat.traceback[0]
        # replace "/path/to/module/file.py" with "module/file.py"
        filename = os.sep.join(frame.filename.split(os.sep)[-2:])
        print("#%s: %s:%s: %.1f KiB"
              % (index, filename, frame.lineno, stat.size / 1024))
        line = linecache.getline(frame.filename, frame.lineno).strip()
        if line:
            print('    %s' % line)

    other = top_stats[limit:]
    if other:
        size = sum(stat.size for stat in other)
        print("%s other: %.1f KiB" % (len(other), size / 1024))
    total = sum(stat.size for stat in top_stats)
    print("Total allocated size: %.1f KiB" % (total / 1024))


main()

जब मैं उस संस्करण को चलाता हूं, तो मेमोरी उपयोग 6MB से 4KB तक चला गया है, क्योंकि फ़ंक्शन ने अपनी सभी मेमोरी को समाप्त कर दिया।

Top prefixes: [('con', 1220), ('dis', 1002), ('pro', 809)]
Top 3 lines
#1: collections/__init__.py:537: 0.7 KiB
    self.update(*args, **kwds)
#2: collections/__init__.py:555: 0.6 KiB
    return _heapq.nlargest(n, self.items(), key=_itemgetter(1))
#3: python3.6/heapq.py:569: 0.5 KiB
    result = [(key(elem), i, elem) for i, elem in zip(range(0, -n, -1), it)]
10 other: 2.2 KiB
Total allocated size: 4.0 KiB

अब यहां एक अन्य उत्तर से प्रेरित एक संस्करण है जो मेमोरी उपयोग की निगरानी के लिए एक दूसरा धागा शुरू करता है।

from collections import Counter
import linecache
import os
import tracemalloc
from datetime import datetime
from queue import Queue, Empty
from resource import getrusage, RUSAGE_SELF
from threading import Thread
from time import sleep

def memory_monitor(command_queue: Queue, poll_interval=1):
    tracemalloc.start()
    old_max = 0
    snapshot = None
    while True:
        try:
            command_queue.get(timeout=poll_interval)
            if snapshot is not None:
                print(datetime.now())
                display_top(snapshot)

            return
        except Empty:
            max_rss = getrusage(RUSAGE_SELF).ru_maxrss
            if max_rss > old_max:
                old_max = max_rss
                snapshot = tracemalloc.take_snapshot()
                print(datetime.now(), 'max RSS', max_rss)


def count_prefixes():
    sleep(2)  # Start up time.
    counts = Counter()
    fname = '/usr/share/dict/american-english'
    with open(fname) as words:
        words = list(words)
        for word in words:
            prefix = word[:3]
            counts[prefix] += 1
            sleep(0.0001)
    most_common = counts.most_common(3)
    sleep(3)  # Shut down time.
    return most_common


def main():
    queue = Queue()
    poll_interval = 0.1
    monitor_thread = Thread(target=memory_monitor, args=(queue, poll_interval))
    monitor_thread.start()
    try:
        most_common = count_prefixes()
        print('Top prefixes:', most_common)
    finally:
        queue.put('stop')
        monitor_thread.join()


def display_top(snapshot, key_type='lineno', limit=3):
    snapshot = snapshot.filter_traces((
        tracemalloc.Filter(False, "<frozen importlib._bootstrap>"),
        tracemalloc.Filter(False, "<unknown>"),
    ))
    top_stats = snapshot.statistics(key_type)

    print("Top %s lines" % limit)
    for index, stat in enumerate(top_stats[:limit], 1):
        frame = stat.traceback[0]
        # replace "/path/to/module/file.py" with "module/file.py"
        filename = os.sep.join(frame.filename.split(os.sep)[-2:])
        print("#%s: %s:%s: %.1f KiB"
              % (index, filename, frame.lineno, stat.size / 1024))
        line = linecache.getline(frame.filename, frame.lineno).strip()
        if line:
            print('    %s' % line)

    other = top_stats[limit:]
    if other:
        size = sum(stat.size for stat in other)
        print("%s other: %.1f KiB" % (len(other), size / 1024))
    total = sum(stat.size for stat in top_stats)
    print("Total allocated size: %.1f KiB" % (total / 1024))


main()

resourceमॉड्यूल आप मौजूदा स्मृति के उपयोग की जाँच करें, और चोटी स्मृति के उपयोग से स्नैपशॉट सहेजने देता है। कतार अपनी रिपोर्ट को प्रिंट करने और बंद करने के लिए मुख्य थ्रेड को मेमोरी मॉनिटर थ्रेड को बताने देती है। जब यह चलता है, तो यह list()कॉल द्वारा उपयोग की जा रही मेमोरी दिखाता है :

2018-05-29 10:34:34.441334 max RSS 10188
2018-05-29 10:34:36.475707 max RSS 23588
2018-05-29 10:34:36.616524 max RSS 38104
2018-05-29 10:34:36.772978 max RSS 45924
2018-05-29 10:34:36.929688 max RSS 46824
2018-05-29 10:34:37.087554 max RSS 46852
Top prefixes: [('con', 1220), ('dis', 1002), ('pro', 809)]
2018-05-29 10:34:56.281262
Top 3 lines
#1: scratches/scratch.py:36: 6527.0 KiB
    words = list(words)
#2: scratches/scratch.py:38: 16.4 KiB
    prefix = word[:3]
#3: scratches/scratch.py:39: 10.1 KiB
    counts[prefix] += 1
19 other: 10.8 KiB
Total allocated size: 6564.3 KiB

यदि आप लिनक्स पर हैं, तो आप मॉड्यूल की /proc/self/statmतुलना में अधिक उपयोगी हो सकते हैं resource


यह बहुत अच्छा है, लेकिन यह केवल अंतरालों के दौरान स्नैपशॉट प्रिंट करने के लिए लगता है जब "count_prefixes ()" रिटर्न के अंदर कार्य करता है। दूसरे शब्दों में, यदि आपके पास कुछ लंबी चलने वाली कॉल है, उदाहरण long_running()के लिए count_prefixes()फ़ंक्शन के अंदर , अधिकतम आरएसएस मूल्यों को long_running()रिटर्न तक प्रिंट नहीं किया जाएगा । या मैं गलत हूँ?
डकैतपन

मुझे लगता है कि आप गलत हैं, @robguinness। memory_monitor()से एक अलग थ्रेड पर चल रहा है count_prefixes(), इसलिए एकमात्र तरीका जो दूसरे को प्रभावित कर सकता है वह है GIL और संदेश पंक्ति जो मैं पास करता हूं memory_monitor()। मुझे संदेह है कि जब count_prefixes()कॉल करता है sleep(), तो यह थ्रेड संदर्भ को स्विच करने के लिए प्रोत्साहित करता है। यदि आपका long_running()वास्तव में बहुत लंबा समय नहीं ले रहा है, तो थ्रेड संदर्भ तब तक स्विच नहीं हो सकता जब तक आप sleep()कॉल को वापस नहीं मारते count_prefixes()। अगर इससे कोई मतलब नहीं है, तो एक नया सवाल पोस्ट करें और इसे यहां से लिंक करें।
डॉन किर्कबी

धन्यवाद। मैं एक नया प्रश्न पोस्ट करूंगा और यहां एक लिंक जोड़ूंगा। (मुझे समस्या का एक उदाहरण काम करने की आवश्यकता है, क्योंकि मैं कोड के मालिकाना भागों को साझा नहीं कर सकता हूं।)
8

31

यदि आप किसी ऑब्जेक्ट के मेमोरी उपयोग को देखना चाहते हैं, ( अन्य प्रश्न का उत्तर )

एक मॉड्यूल है जिसे Pympler कहा जाता है जिसमें asizeof मॉड्यूल होता है ।

निम्नानुसार उपयोग करें:

from pympler import asizeof
asizeof.asizeof(my_object)

इसके विपरीत sys.getsizeof, यह आपकी स्व-निर्मित वस्तुओं के लिए काम करता है

>>> asizeof.asizeof(tuple('bcd'))
200
>>> asizeof.asizeof({'foo': 'bar', 'baz': 'bar'})
400
>>> asizeof.asizeof({})
280
>>> asizeof.asizeof({'foo':'bar'})
360
>>> asizeof.asizeof('foo')
40
>>> asizeof.asizeof(Bar())
352
>>> asizeof.asizeof(Bar().__dict__)
280
>>> help(asizeof.asizeof)
Help on function asizeof in module pympler.asizeof:

asizeof(*objs, **opts)
    Return the combined size in bytes of all objects passed as positional arguments.

1
क्या यह असोसोफ आरएसएस से संबंधित है?
pg2455

1
@mousecoder: en.wikipedia.org/wiki/RSS_(disambiguation पर कौन सा RSS ) ? वेब फ़ीड? कैसे?
सर्व-इंक

2
@ सर्व-इंक रेजिडेंट सेट का आकार , हालाँकि मुझे इसका केवल एक ही उल्लेख पिंपलर के स्रोत में मिल सकता है और यह उल्लेख सीधे-बंधे नहीं लगता हैasizeof
jkmartindale

1
@mousecoder द्वारा बताई गई मेमोरी asizeofRSS में योगदान दे सकती है, हाँ। मुझे यकीन नहीं है कि आप "संबंधित" से क्या मतलब है।
ऑरेंजडॉग

1
@ सर्व-संभव इसके मामले बहुत विशिष्ट हो सकते हैं। लेकिन मेरे usecase के लिए एक बड़े बहुआयामी शब्दकोश को मापने के लिए, मुझे tracemallocएक परिमाण के नीचे तेजी से समाधान मिला
ulkas

22

प्रकटीकरण:

  • लिनक्स पर ही लागू है
  • वर्तमान प्रक्रिया द्वारा उपयोग की जाने वाली मेमोरी को संपूर्ण रूप से, व्यक्तिगत कार्यों को नहीं

लेकिन अपनी सादगी के कारण अच्छा है:

import resource
def using(point=""):
    usage=resource.getrusage(resource.RUSAGE_SELF)
    return '''%s: usertime=%s systime=%s mem=%s mb
           '''%(point,usage[0],usage[1],
                usage[2]/1024.0 )

बस वह डालें using("Label")जहाँ आप देखना चाहते हैं कि क्या हो रहा है। उदाहरण के लिए

print(using("before"))
wrk = ["wasting mem"] * 1000000
print(using("after"))

>>> before: usertime=2.117053 systime=1.703466 mem=53.97265625 mb
>>> after: usertime=2.12023 systime=1.70708 mem=60.8828125 mb

6
"दिए गए फ़ंक्शन का मेमोरी उपयोग" इसलिए आपका दृष्टिकोण मदद नहीं कर रहा है।
ग्लास्लो

को देख कर usage[2]आप देख रहे हैं ru_maxrssजो केवल प्रक्रिया है जिसके है का एक हिस्सा है निवासी । यह बहुत मदद नहीं करेगा अगर प्रक्रिया को डिस्क में स्वैप किया गया है, यहां तक ​​कि आंशिक रूप से भी।
लुई

8
resourceएक यूनिक्स विशिष्ट मॉड्यूल है जो विंडोज के तहत काम नहीं करता है।
मार्टिन

1
की इकाइयाँ ru_maxrss(जो है usage[2]) kB हैं, पृष्ठ नहीं हैं, इसलिए उस संख्या को गुणा करने की कोई आवश्यकता नहीं है resource.getpagesize()
T ''

1
इसने मेरे लिए कुछ भी नहीं छापा।
क्वांटमोटोटो

7

चूँकि स्वीकृत उत्तर और साथ ही अगले सर्वोच्च मतदान के उत्तर में, मेरी राय में, कुछ समस्याएं हैं, मैं एक और उत्तर देना चाहूंगा जो कि कुछ छोटे लेकिन महत्वपूर्ण संशोधनों के साथ Ihor बी के उत्तर पर आधारित है।

यह समाधान आपको फ़ंक्शन के साथ फ़ंक्शन कॉल लपेटकर या इसे कॉल करके, या डेकोरेटर के साथ अपने फ़ंक्शन / विधि को सजाने के द्वारा या तो प्रोफाइलिंग चलाने की अनुमति देता है ।profile@profile

पहली तकनीक तब उपयोगी होती है जब आप किसी थर्ड-पार्टी कोड को उसके स्रोत के साथ खिलवाड़ किए बिना प्रोफाइल करना चाहते हैं, जबकि दूसरी तकनीक थोड़ी "क्लीनर" है और जब आप फ़ंक्शन / विधि के स्रोत को संशोधित करने में मन नहीं लगाते हैं तो बेहतर काम करता है प्रोफाइल बनाना चाहते हैं।

मैंने आउटपुट को भी संशोधित किया है, ताकि आपको RSS, VMS और साझा की गई मेमोरी मिल जाए। मैं "पहले" और "बाद" मूल्यों के बारे में बहुत परवाह नहीं करता, लेकिन केवल डेल्टा, इसलिए मैंने उन लोगों को हटा दिया (यदि आप Ihor बी के उत्तर की तुलना कर रहे हैं)।

प्रोफाइलिंग कोड

# profile.py
import time
import os
import psutil
import inspect


def elapsed_since(start):
    #return time.strftime("%H:%M:%S", time.gmtime(time.time() - start))
    elapsed = time.time() - start
    if elapsed < 1:
        return str(round(elapsed*1000,2)) + "ms"
    if elapsed < 60:
        return str(round(elapsed, 2)) + "s"
    if elapsed < 3600:
        return str(round(elapsed/60, 2)) + "min"
    else:
        return str(round(elapsed / 3600, 2)) + "hrs"


def get_process_memory():
    process = psutil.Process(os.getpid())
    mi = process.memory_info()
    return mi.rss, mi.vms, mi.shared


def format_bytes(bytes):
    if abs(bytes) < 1000:
        return str(bytes)+"B"
    elif abs(bytes) < 1e6:
        return str(round(bytes/1e3,2)) + "kB"
    elif abs(bytes) < 1e9:
        return str(round(bytes / 1e6, 2)) + "MB"
    else:
        return str(round(bytes / 1e9, 2)) + "GB"


def profile(func, *args, **kwargs):
    def wrapper(*args, **kwargs):
        rss_before, vms_before, shared_before = get_process_memory()
        start = time.time()
        result = func(*args, **kwargs)
        elapsed_time = elapsed_since(start)
        rss_after, vms_after, shared_after = get_process_memory()
        print("Profiling: {:>20}  RSS: {:>8} | VMS: {:>8} | SHR {"
              ":>8} | time: {:>8}"
            .format("<" + func.__name__ + ">",
                    format_bytes(rss_after - rss_before),
                    format_bytes(vms_after - vms_before),
                    format_bytes(shared_after - shared_before),
                    elapsed_time))
        return result
    if inspect.isfunction(func):
        return wrapper
    elif inspect.ismethod(func):
        return wrapper(*args,**kwargs)

उदाहरण उपयोग, ऊपर दिए गए कोड को इस प्रकार सहेजा गया है profile.py:

from profile import profile
from time import sleep
from sklearn import datasets # Just an example of 3rd party function call


# Method 1
run_profiling = profile(datasets.load_digits)
data = run_profiling()

# Method 2
@profile
def my_function():
    # do some stuff
    a_list = []
    for i in range(1,100000):
        a_list.append(i)
    return a_list


res = my_function()

यह नीचे के समान आउटपुट में होना चाहिए:

Profiling:        <load_digits>  RSS:   5.07MB | VMS:   4.91MB | SHR  73.73kB | time:  89.99ms
Profiling:        <my_function>  RSS:   1.06MB | VMS:   1.35MB | SHR       0B | time:   8.43ms

महत्वपूर्ण अंतिम नोटों की एक जोड़ी:

  1. ध्यान रखें, प्रोफाइलिंग का यह तरीका केवल अनुमानित है, क्योंकि मशीन पर बहुत सारे अन्य सामान हो सकते हैं। कचरा संग्रहण और अन्य कारकों के कारण, डेल्टास शून्य भी हो सकता है।
  2. किसी अज्ञात कारण से, बहुत कम फ़ंक्शन कॉल (जैसे 1 या 2 एमएस) शून्य मेमोरी उपयोग के साथ दिखाई देते हैं। मुझे संदेह है कि यह हार्डवेयर / ओएस (लिनक्स के साथ बुनियादी लैपटॉप पर परीक्षण) की कुछ सीमा है कि मेमोरी के आँकड़े कितनी बार अपडेट किए जाते हैं।
  3. उदाहरणों को सरल रखने के लिए, मैंने किसी भी फ़ंक्शन तर्क का उपयोग नहीं किया, लेकिन उन्हें profile(my_function, arg)प्रोफ़ाइल के अनुसार अपेक्षा के अनुसार काम करना चाहिए my_function(arg)

7

नीचे एक साधारण फंक्शन डेकोरेटर है, जो यह बताता है कि फंक्शन कॉल से पहले, फंक्शन कॉल के बाद, और क्या अंतर है, कितनी मेमोरी का उपयोग किया जाता है।

import time
import os
import psutil


def elapsed_since(start):
    return time.strftime("%H:%M:%S", time.gmtime(time.time() - start))


def get_process_memory():
    process = psutil.Process(os.getpid())
    return process.get_memory_info().rss


def profile(func):
    def wrapper(*args, **kwargs):
        mem_before = get_process_memory()
        start = time.time()
        result = func(*args, **kwargs)
        elapsed_time = elapsed_since(start)
        mem_after = get_process_memory()
        print("{}: memory before: {:,}, after: {:,}, consumed: {:,}; exec time: {}".format(
            func.__name__,
            mem_before, mem_after, mem_after - mem_before,
            elapsed_time))
        return result
    return wrapper

यहाँ मेरा ब्लॉग है जो सभी विवरणों का वर्णन करता है। ( संग्रहीत लिंक )


4
यह कम से कम उबंटू और अजगर 3.6 में process.memory_info().rssनहीं होना चाहिए process.get_memory_info().rss। संबंधित stackoverflow.com/questions/41012058/psutil-error-on-macos
jangorecki

1
आप 3.x तक सही हैं। मेरा ग्राहक पायथन 2.7 का उपयोग कर रहा है, नवीनतम संस्करण का नहीं।
इहोर बी।

4

शायद यह मदद करता है:
< अतिरिक्त देखें >

pip install gprof2dot
sudo apt-get install graphviz

gprof2dot -f pstats profile_for_func1_001 | dot -Tpng -o profile.png

def profileit(name):
    """
    @profileit("profile_for_func1_001")
    """
    def inner(func):
        def wrapper(*args, **kwargs):
            prof = cProfile.Profile()
            retval = prof.runcall(func, *args, **kwargs)
            # Note use of name from outer scope
            prof.dump_stats(name)
            return retval
        return wrapper
    return inner

@profileit("profile_for_func1_001")
def func1(...)

1

कोड के एक ब्लॉक के मेमोरी उपयोग की गणना करने के लिए एक सरल उदाहरण / फ़ंक्शन का रिटर्न करते समय मेमोरी_प्रोफाइल का उपयोग करते हुए:

import memory_profiler as mp

def fun(n):
    tmp = []
    for i in range(n):
        tmp.extend(list(range(i*i)))
    return "XXXXX"

कोड चलाने से पहले मेमोरी उपयोग की गणना करें और फिर कोड के दौरान अधिकतम उपयोग की गणना करें:

start_mem = mp.memory_usage(max_usage=True)
res = mp.memory_usage(proc=(fun, [100]), max_usage=True, retval=True) 
print('start mem', start_mem)
print('max mem', res[0][0])
print('used mem', res[0][0]-start_mem)
print('fun output', res[1])

फ़ंक्शन चलाते समय नमूना बिंदुओं में उपयोग की गणना करें:

res = mp.memory_usage((fun, [100]), interval=.001, retval=True)
print('min mem', min(res[0]))
print('max mem', max(res[0]))
print('used mem', max(res[0])-min(res[0]))
print('fun output', res[1])

क्रेडिट: @skeept

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.