Làm cách nào để cấu hình sử dụng bộ nhớ trong Python?


230

Gần đây tôi đã trở nên quan tâm đến các thuật toán và đã bắt đầu khám phá chúng bằng cách viết một triển khai ngây thơ và sau đó tối ưu hóa nó theo nhiều cách khác nhau.

Tôi đã quen thuộc với mô-đun Python tiêu chuẩn để định hình thời gian chạy (đối với hầu hết mọi thứ tôi đã thấy hàm ma thuật thời gian trong IPython là đủ), nhưng tôi cũng quan tâm đến việc sử dụng bộ nhớ để tôi cũng có thể khám phá những sự đánh đổi đó ( ví dụ: chi phí lưu trữ một bảng các giá trị được tính toán trước đó so với tính toán lại chúng khi cần thiết). Có một mô-đun nào sẽ cấu hình việc sử dụng bộ nhớ của một chức năng nhất định cho tôi không?


Bản sao của trình biên dịch bộ nhớ Python nào được khuyến nghị? . Câu trả lời hay nhất của IMHO năm 2019 là memory_profiler
vladkha

Câu trả lời:


118

Điều này đã được trả lời ở đây: Trình hồ sơ bộ nhớ Python

Về cơ bản, bạn làm một cái gì đó như thế (được trích dẫn từ Guppy-PE ):

>>> 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
Tài liệu guppy chính thức là một chút tối thiểu; cho các tài nguyên khác xem ví dụ nàybài tiểu luận heapy .
tutuDajuju

14
Guppy dường như không còn được duy trì, vì vậy tôi đề nghị câu trả lời này được hạ cấp và một trong những câu trả lời khác được chấp nhận thay thế.
cướp

1
@robguinness Bằng cách hạ cấp bạn có nghĩa là bỏ phiếu? Điều đó có vẻ không công bằng bởi vì nó có giá trị tại một thời điểm. Tôi nghĩ rằng một chỉnh sửa ở trên cùng cho biết nó không còn hợp lệ vì lý do X và để xem câu trả lời Y hoặc Z thay thế. Tôi nghĩ rằng quá trình hành động này là phù hợp hơn.
WinEunuuchs2Unix

1
Chắc chắn, điều đó cũng hoạt động, nhưng bằng cách nào đó sẽ tốt đẹp nếu câu trả lời được chấp nhận và được bình chọn cao nhất liên quan đến một giải pháp vẫn hoạt động và được duy trì.
cướp

92

Python 3,4 bao gồm một mô-đun mới : tracemalloc. Nó cung cấp số liệu thống kê chi tiết về mã nào được phân bổ nhiều bộ nhớ nhất. Dưới đây là một ví dụ hiển thị ba dòng cấp phát bộ nhớ hàng đầu.

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)

Và đây là kết quả:

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

Khi nào rò rỉ bộ nhớ không phải là rò rỉ?

Ví dụ đó thật tuyệt vời khi bộ nhớ vẫn được giữ ở cuối phép tính, nhưng đôi khi bạn có mã phân bổ rất nhiều bộ nhớ và sau đó giải phóng tất cả. Về mặt kỹ thuật, nó không bị rò rỉ bộ nhớ, nhưng nó sử dụng nhiều bộ nhớ hơn bạn nghĩ. Làm thế nào bạn có thể theo dõi việc sử dụng bộ nhớ khi tất cả được phát hành? Nếu đó là mã của bạn, có lẽ bạn có thể thêm một số mã gỡ lỗi để chụp ảnh nhanh trong khi nó đang chạy. Nếu không, bạn có thể bắt đầu một luồng nền để theo dõi việc sử dụng bộ nhớ trong khi luồng chính chạy.

Đây là ví dụ trước đây trong đó tất cả mã đã được chuyển vào count_prefixes()hàm. Khi chức năng đó trở lại, tất cả bộ nhớ được giải phóng. Tôi cũng đã thêm một số sleep()cuộc gọi để mô phỏng một phép tính dài hạn.

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()

Khi tôi chạy phiên bản đó, việc sử dụng bộ nhớ đã giảm từ 6MB xuống 4KB, vì chức năng này đã giải phóng tất cả bộ nhớ của nó khi kết thúc.

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

Bây giờ đây là một phiên bản lấy cảm hứng từ một câu trả lời khác bắt đầu một luồng thứ hai để theo dõi việc sử dụng bộ nhớ.

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()

Các resourcemô-đun cho phép bạn kiểm tra việc sử dụng bộ nhớ hiện tại, và lưu ảnh chụp từ việc sử dụng bộ nhớ cao điểm. Hàng đợi cho phép luồng chính báo luồng xử lý bộ nhớ khi in báo cáo và tắt. Khi chạy, nó hiển thị bộ nhớ đang được sử dụng bởi list()cuộc gọi:

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

Nếu bạn đang dùng Linux, bạn có thể thấy /proc/self/statmhữu ích hơn resourcemô-đun.


Điều này thật tuyệt, nhưng dường như chỉ in các ảnh chụp nhanh trong các khoảng thời gian khi các hàm bên trong "Count_prefixes ()" trở lại. Nói cách khác, nếu bạn có một số cuộc gọi chạy dài, ví dụ long_running()bên trong count_prefixes()hàm, các giá trị RSS tối đa sẽ không được in cho đến khi long_running()trả về. Hay là tôi nhầm?
cướp

Tôi nghĩ bạn đã nhầm, @robguinness. memory_monitor()đang chạy trên một luồng riêng biệt count_prefixes(), vì vậy cách duy nhất mà người ta có thể ảnh hưởng đến người khác là GIL và hàng đợi tin nhắn mà tôi chuyển đến memory_monitor(). Tôi nghi ngờ rằng khi count_prefixes()các cuộc gọi sleep(), nó khuyến khích bối cảnh luồng để chuyển đổi. Nếu bạn long_running()không thực sự mất nhiều thời gian, thì ngữ cảnh luồng có thể không chuyển cho đến khi bạn thực hiện sleep()lại cuộc gọi count_prefixes(). Nếu điều đó không có ý nghĩa, hãy đăng một câu hỏi mới và liên kết với nó từ đây.
Don Kirkby

Cảm ơn. Tôi sẽ đăng một câu hỏi mới và thêm một liên kết ở đây. (Tôi cần đưa ra một ví dụ về vấn đề tôi đang gặp phải, vì tôi không thể chia sẻ các phần độc quyền của mã.)
robguinness

31

Nếu bạn chỉ muốn xem việc sử dụng bộ nhớ của một đối tượng, ( trả lời cho câu hỏi khác )

Có một mô-đun gọi là Pympler chứaasizeof mô-đun.

Sử dụng như sau:

from pympler import asizeof
asizeof.asizeof(my_object)

Không giống như sys.getsizeof, nó hoạt động cho các đối tượng tự tạo của bạn .

>>> 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
Đây có phải là asizeof liên quan đến RSS?
pg2455

1
@mousecoder: RSS nào tại en.wikipedia.org/wiki/RSS_(disambiginating) ? Nguồn cấp dữ liệu web? Làm sao?
serv-inc

2
@ serv-inc Kích thước cài đặt thường trú , mặc dù tôi chỉ có thể tìm thấy một đề cập về nó trong nguồn của Pympler và đề cập đó dường như không liên quan trực tiếp đếnasizeof
jkmartindale

1
@mousecoder bộ nhớ được báo cáo bởi asizeofcó thể đóng góp cho RSS, vâng. Tôi không chắc bạn có ý gì khác khi "liên quan đến".
OrangeDog

1
@ serv-inc có thể nó có thể rất cụ thể. nhưng đối với usecase của tôi đo một từ điển đa chiều lớn, tôi đã tìm thấy tracemallocgiải pháp dưới một cường độ nhanh hơn
ulkas

22

Tiết lộ:

  • Chỉ áp dụng trên Linux
  • Báo cáo bộ nhớ được sử dụng bởi toàn bộ quá trình hiện tại, không phải các chức năng riêng lẻ trong

Nhưng tốt đẹp vì sự đơn giản của nó:

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 )

Chỉ cần chèn vào using("Label")nơi bạn muốn xem những gì đang xảy ra. Ví dụ

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
"Sử dụng bộ nhớ của một chức năng nhất định" để cách tiếp cận của bạn không có ích.
Graffitilos

Bằng cách nhìn vào usage[2]bạn đang nhìn ru_maxrss, đó chỉ là một phần của quá trình cư trú . Điều này sẽ không giúp ích nhiều nếu quá trình đã được hoán đổi vào đĩa, thậm chí một phần.
Louis

8
resourcelà một mô-đun cụ thể Unix không hoạt động trong Windows.
Martin

1
Đơn vị của ru_maxrss(nghĩa là usage[2]) là kB, không phải trang nên không cần nhân số đó với resource.getpagesize().
Tey '

1
Điều này in ra không có gì cho tôi.
quantumpotato

7

Vì câu trả lời được chấp nhận và cũng là câu trả lời được bình chọn cao nhất tiếp theo, theo tôi, một số vấn đề, tôi muốn đưa ra một câu trả lời dựa trên câu trả lời của Ihor B. với một số sửa đổi nhỏ nhưng quan trọng.

Giải pháp này cho phép bạn chạy hồ sơ trên một trong hai cách gọi hàm với profilehàm và gọi nó, hoặc bằng cách trang trí hàm / phương thức của bạn với trình @profiletrang trí.

Kỹ thuật thứ nhất rất hữu ích khi bạn muốn cấu hình một số mã của bên thứ ba mà không gây rối với nguồn của nó, trong khi kỹ thuật thứ hai hơi "sạch" hơn và hoạt động tốt hơn khi bạn không ngại sửa đổi nguồn của hàm / phương thức bạn muốn hồ sơ.

Tôi cũng đã sửa đổi đầu ra, để bạn có được RSS, VMS và bộ nhớ dùng chung. Tôi không quan tâm nhiều đến các giá trị "trước" và "sau", mà chỉ là đồng bằng, vì vậy tôi đã loại bỏ các giá trị đó (nếu bạn đang so sánh với câu trả lời của Ihor B.).

Mã hồ sơ

# 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)

Ví dụ sử dụng, giả sử mã trên được lưu dưới dạng 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()

Điều này sẽ dẫn đến đầu ra tương tự như dưới đây:

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

Một vài lưu ý quan trọng cuối cùng:

  1. Hãy nhớ rằng, phương pháp định hình này sẽ chỉ là gần đúng, vì rất nhiều thứ khác có thể xảy ra trên máy. Do thu gom rác và các yếu tố khác, đồng bằng thậm chí có thể bằng không.
  2. Đối với một số lý do không xác định, các lệnh gọi hàm rất ngắn (ví dụ 1 hoặc 2 ms) hiển thị với mức sử dụng bộ nhớ bằng không. Tôi nghi ngờ đây là một số hạn chế của phần cứng / HĐH (được thử nghiệm trên máy tính xách tay cơ bản với Linux) về tần suất thống kê bộ nhớ được cập nhật.
  3. Để giữ cho các ví dụ đơn giản, tôi đã không sử dụng bất kỳ đối số chức năng nào, nhưng chúng nên hoạt động như người ta mong đợi, tức là profile(my_function, arg)để hồ sơmy_function(arg)

7

Dưới đây là một trình trang trí chức năng đơn giản cho phép theo dõi bao nhiêu bộ nhớ mà quá trình tiêu thụ trước khi gọi hàm, sau khi gọi hàm và sự khác biệt là gì:

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

Đây là blog của tôi mô tả tất cả các chi tiết. ( liên kết lưu trữ )


4
nó phải process.memory_info().rsskhông process.get_memory_info().rss, ít nhất là trong ubuntu và python 3.6. liên quan stackoverflow.com/questions/41012058/psutil-error-on-macos
jangorecki

1
Bạn đúng như 3.x. Khách hàng của tôi đang sử dụng Python 2.7, không phải phiên bản mới nhất.
Ihor B.

4

có thể nó giúp:
< xem thêm >

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

Một ví dụ đơn giản để tính toán mức sử dụng bộ nhớ của một khối mã / hàm bằng memory_profile, trong khi trả về kết quả của hàm:

import memory_profiler as mp

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

tính toán mức sử dụng bộ nhớ trước khi chạy mã sau đó tính toán mức sử dụng tối đa trong mã:

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])

tính toán sử dụng trong các điểm lấy mẫu trong khi chạy chức năng:

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])

Tín dụng: @skeept

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.