পাইথনে আমি মেমরির ব্যবহার কীভাবে করব?


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 ডাউনগ্রেড করে আপনি নীচে ভোট পেয়েছেন? এটি ন্যায্য বলে মনে হচ্ছে না কারণ এটি এক সময় মূল্যবান ছিল। আমি মনে করি যে শীর্ষে একটি সম্পাদনা উল্লেখ করা হয়েছে যে এটি এক্স কারণে এবং এর পরিবর্তে Y বা Z জবাব দেখার পক্ষে বৈধ নয়। আমি মনে করি ক্রিয়াটির এই কোর্সটি আরও উপযুক্ত।
WinEunuuchs2 ইউনিক্স

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মডিউলটির চেয়ে আপনি আরও দরকারী ।


এটি দুর্দান্ত, তবে "কাউন্টি_প্রিফিক্স ()" এর অভ্যন্তরে যখন ফাংশনগুলি ফাংশন করে তখন কেবল বিরতিগুলির সময় স্ন্যাপশটগুলি প্রিন্ট করা হবে বলে মনে হয়। অন্য কথায়, আপনি কিছু দীর্ঘ চলমান কল, যেমন আছে যদি long_running()ভিতরে count_prefixes()ফাংশন, সর্বোচ্চ আরএসএস মান পর্যন্ত মুদ্রিত হবে না long_running()আয়। নাকি আমি ভুল করছি?
রবগুইননেস

আমি ভেবেছি আপনি ভুল করেছেন, @ আরবগুইননেস। memory_monitor()এর থেকে পৃথক থ্রেডে চলছে count_prefixes(), সুতরাং অন্য যে কোনও একটিকে প্রভাবিত করতে পারে তার একমাত্র উপায় হ'ল জিআইএল এবং আমি যে বার্তাগুলি দিয়েছি memory_monitor()। আমি সন্দেহ করি যে count_prefixes()কল sleep()করার সময় এটি থ্রেড প্রসঙ্গটি স্যুইচ করতে উত্সাহ দেয়। যদি আপনার long_running()প্রকৃতপক্ষে খুব বেশি সময় নিচ্ছে না, তবে আপনি sleep()কলটি পুনরায় কল না করা পর্যন্ত থ্রেড প্রসঙ্গটি পরিবর্তন হতে পারে count_prefixes()। যদি তা বোঝা না যায় তবে একটি নতুন প্রশ্ন পোস্ট করুন এবং এখান থেকে এটিতে লিঙ্ক করুন।
ডন কার্কবি

ধন্যবাদ। আমি একটি নতুন প্রশ্ন পোস্ট করব এবং এখানে একটি লিঙ্ক যুক্ত করব। (আমি যে সমস্যাটি নিয়েছি তার একটি উদাহরণ আমার হাতে নেওয়া দরকার, যেহেতু আমি কোডের স্বত্বাধিকারী অংশগুলি ভাগ করতে পারি না))
রোবগুইনেস

31

আপনি যদি কেবল কোনও জিনিসের মেমরির ব্যবহারটি দেখতে চান তবে ( অন্যান্য প্রশ্নের উত্তর )

পাইম্পলার নামে একটি মডিউল রয়েছে যার মধ্যে 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
এই asizeof কি আরএসএস সম্পর্কিত?
pg2455

1
@mousecoder: এ কোন আরএসএস en.wikipedia.org/wiki/RSS_(disambiguation) ? ওয়েব ফিডস? কিভাবে?
সার্ভ-ইন

2
@ সার্ভ-ইনসিড রেসিডেন্ট সেট আকার , যদিও আমি কেবল এটির একটি উল্লেখ পাইম্পলারের উত্সে খুঁজে পেতে পারি এবং সে উল্লেখটি সরাসরি জড়িত বলে মনে হয় নাasizeof
jkmartindale

1
@ মাউসকোডার জানিয়েছেন মেমোরিটি asizeofআরএসএসে অবদান রাখতে পারে, হ্যাঁ। "সম্পর্কিত" দ্বারা আপনি কী বোঝাতে চেয়েছেন তা আমি নিশ্চিত নই।
অরেঞ্জডগ

1
@ সার্ভ-ইন এটি সম্ভব এটি খুব কেস নির্দিষ্ট হতে পারে। তবে আমার ইউসকেসটি একটি বৃহত বহুমাত্রিক অভিধান পরিমাপ করার জন্য, আমি tracemallocদ্রুততর মাত্রার নীচে সমাধান খুঁজে পেয়েছি
উলকাস

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")কী চলছে তা দেখতে কেবল sertোকান । উদাহরণ স্বরূপ

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যা শুধুমাত্র প্রক্রিয়া যার হয় তা হল, বাসিন্দা । প্রক্রিয়াটি ডিস্কে এমনকি আংশিকভাবে অদলবদল করা থাকলে এটি বেশি সাহায্য করবে না।
লুই 18

8
resourceএকটি ইউনিক্স নির্দিষ্ট মডিউল যা উইন্ডোজের অধীনে কাজ করে না।
মার্টিন

1
ru_maxrss(যেটি হ'ল usage[2]) এর ইউনিটগুলি কেবি, পৃষ্ঠাগুলি নয় তাই সেই সংখ্যাটি কোনও দ্বারা গুণানোর দরকার নেই resource.getpagesize()
'

1
এটি আমার জন্য কিছুই ছাপেনি।
কোয়ান্টাম্পোটাটো

7

যেহেতু গৃহীত উত্তর এবং পরবর্তী সর্বোচ্চ ভোট প্রাপ্ত উত্তরগুলিও আমার মতে কিছু সমস্যা রয়েছে তাই আমি আরও একটি উত্তর দিতে চাই যা ইহোর বি'র উত্তরের উপর ভিত্তি করে কিছু ছোট কিন্তু গুরুত্বপূর্ণ পরিবর্তন রয়েছে।

এই সমাধান আপনার উপর প্রোফাইলিং চালাতে সক্ষম হয় সাথে একটি ফাংশন কল মোড়কে profileফাংশন এবং এটি আহ্বান, বা সঙ্গে আপনার ফাংশন / পদ্ধতি শোভাকর দ্বারা@profile প্রসাধক।

প্রথম কৌশলটি কার্যকর যখন আপনি কোনও উত্সটির সাথে জগাখিচুবি না করে কিছু তৃতীয় পক্ষের কোডটি প্রোফাইল করতে চান, যখন দ্বিতীয় কৌশলটি কিছুটা "ক্লিনার" এবং যখন আপনি ফাংশন / পদ্ধতির উত্সটি পরিবর্তন করতে আপত্তি করেন না তখন আপনি আরও ভাল কাজ করেন you প্রোফাইল করতে চান

আমি আউটপুটটিও পরিবর্তন করেছি, যাতে আপনি আরএসএস, ভিএমএস এবং ভাগ করা মেমরি পান। আমি "পূর্বে" এবং "পরে" মানগুলি নিয়ে খুব বেশি পাত্তা দিই না, তবে কেবল বদ্বীপ, তাই আমি সেগুলি সরিয়ে দিয়েছি (যদি আপনি ইহোর বি এর উত্তরের সাথে তুলনা করছেন)।

প্রোফাইলিং কোড

# 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)প্রোফাইল হিসাবে প্রত্যাশার মতো কাজ করা উচিত profilemy_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. আমার গ্রাহক পাইথন ২.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])

ক্রেডিট: @ এসকিট

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.