وبلاگ رسانگار
با ما حرفه ای باشید

سرور مجازی NVMe

راهنمای پروفایل سازی اسکریپت های پایتون

0 26
زمان لازم برای مطالعه: 7 دقیقه


معرفی

حتی با یک زبان “ساده” مانند پایتون، از مشکلات عملکرد مصون نیست. همانطور که پایگاه کد شما رشد می کند، ممکن است متوجه شوید که بخش های خاصی از کد شما کندتر از حد انتظار اجرا می شود. اینجاست که نمایه سازی وارد عمل می شود. نمایه سازی یک ابزار مهم در جعبه ابزار هر توسعه دهنده ای است که به شما امکان می دهد گلوگاه ها را در کد خود شناسایی کرده و بر اساس آن بهینه سازی کنید.

پروفایل و چرا باید آن را انجام دهید

پروفایل، در زمینه برنامه نویسی، است process تجزیه و تحلیل کد شما برای درک اینکه منابع محاسباتی در کجا استفاده می شوند. با استفاده از یک نمایه ساز، می توانید بینش هایی در مورد اینکه کدام بخش از کد شما کندتر از حد انتظار اجرا می شود و چرا به دست می آورید. این می تواند به دلایل مختلفی مانند الگوریتم های ناکارآمد، محاسبات غیر ضروری، اشکالات، یا عملیات فشرده حافظه باشد.

توجه داشته باشید: پروفایل و اشکال زدایی عملیات بسیار متفاوتی هستند. با این حال، پروفایل می تواند در process اشکال زدایی زیرا هم می تواند به شما در بهینه سازی کدتان کمک کند و هم مشکلات را از طریق معیارهای عملکرد پیدا کنید.

بیایید یک مثال را در نظر بگیریم. فرض کنید یک اسکریپت پایتون برای تجزیه و تحلیل یک مجموعه داده بزرگ نوشته اید. اسکریپت با زیرمجموعه کوچکی از داده ها به خوبی کار می کند، اما با افزایش اندازه مجموعه داده، اجرای اسکریپت به طور فزاینده ای زمان می برد. این یک نشانه کلاسیک است که اسکریپت شما ممکن است به بهینه سازی نیاز داشته باشد.

در اینجا یک اسکریپت پایتون ساده است که فاکتوریل یک عدد را با استفاده از بازگشت محاسبه می کند:

def factorial(n):
    if n == 0:
        return 1
    else:
        return n * factorial(n-1)

print(factorial(5))

وقتی این اسکریپت را اجرا می کنید، خروجی می دهد 120 که فاکتوریل از 5. با این حال، اگر سعی کنید فاکتوریل یک عدد بسیار بزرگ را محاسبه کنید، بگویید 10000، متوجه خواهید شد که اسکریپت زمان قابل توجهی برای اجرا می برد. این یک نامزد عالی برای پروفایل و بهینه سازی است.

نمایه سازی یک جنبه حیاتی در توسعه نرم افزار است، به ویژه در پایتون که در آن ماهیت پویا زبان گاهی اوقات می تواند منجر به گلوگاه های عملکرد غیرمنتظره شود. خوشبختانه، پایتون یک اکوسیستم غنی از ابزارهای پروفایل ارائه می دهد که می تواند به شما در شناسایی این تنگناها و بهینه سازی کد خود بر این اساس کمک کند.

نمایه ساز داخلی پایتون است cProfile. این یک ماژول است که پروفایل قطعی برنامه های پایتون را ارائه می دهد. نمایه مجموعه‌ای از آمار است که تعداد دفعات و مدت زمان اجرای بخش‌های مختلف برنامه را توصیف می‌کند.

توجه داشته باشید: پروفایل قطعی به این معنی است که هر فراخوانی تابع، بازگشت تابع، استثنا و سایر وظایف فشرده CPU نظارت می شود. این می تواند نمای بسیار دقیقی از عملکرد برنامه شما ارائه دهد، اما همچنین می تواند برنامه شما را کاهش دهد.

یکی دیگر از ابزارهای محبوب پروفایل پایتون این است line_profiler. این ماژول برای انجام پروفایل خط به خط توابع است. Line profiler یک گزارش خط به خط از اجرای زمان به شما می دهد، که می تواند مفیدتر از گزارش عملکرد به عملکردی باشد که cProfile ارائه می دهد.

ابزارهای نمایه سازی دیگری برای پایتون در دسترس هستند، مانند memory_profiler برای پروفایل استفاده از حافظه، py-spy برای نمونه برداری پروفایلر و Py-Spy برای تجسم خروجی پروفایلر. انتخاب ابزار مورد استفاده به نیازهای خاص شما و ماهیت مشکلات عملکردی که با آن روبرو هستید بستگی دارد.

چگونه یک اسکریپت پایتون را نمایه کنیم

اکنون که ابزارهای موجود را پوشش دادیم، بیایید به روش واقعی نمایه کردن یک اسکریپت پایتون برویم. نگاهی به هر دو خواهیم داشت cProfile و line_profiler.

با استفاده از cProfile

ما با داخلی شروع می کنیم cProfile مدول. این ماژول می تواند به عنوان ابزار خط فرمان یا به طور مستقیم در کد شما استفاده شود. ابتدا روش استفاده از آن در کد خود را بررسی خواهیم کرد.

پیشنهاد می‌کنیم بخوانید:  itertools پایتون - compress()، dropwhile()، takewhile() و groupby()

ابتدا وارد کنید cProfile ماژول و اسکریپت خود را در آن اجرا کنید run تابع. در اینجا یک مثال است:

import cProfile
import re

def test_func():
    re.compile("test|sample")

cProfile.run('test_func()')

وقتی این اسکریپت را اجرا می کنید، cProfile جدولی را با تعداد تماس‌های هر تابع، زمان صرف شده در هر تابع و سایر اطلاعات مفید تولید می‌کند.

خروجی ممکن است چیزی شبیه به این باشد:

         234 function calls (229 primitive calls) in 0.001 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    0.001    0.001 <stdin>:1(test_func)
        1    0.000    0.000    0.001    0.001 <string>:1(<module>)
        1    0.000    0.000    0.001    0.001 re.py:192(compile)
        1    0.000    0.000    0.001    0.001 re.py:230(_compile)
        1    0.000    0.000    0.000    0.000 sre_compile.py:228(_compile_charset)
        1    0.000    0.000    0.000    0.000 sre_compile.py:256(_optimize_charset)
        1    0.000    0.000    0.000    0.000 sre_compile.py:433(_compile_info)
        2    0.000    0.000    0.000    0.000 sre_compile.py:546(isstring)
        1    0.000    0.000    0.000    0.000 sre_compile.py:552(_code)
        1    0.000    0.000    0.001    0.001 sre_compile.py:567(compile)
      3/1    0.000    0.000    0.000    0.000 sre_compile.py:64(_compile)
        5    0.000    0.000    0.000    0.000 sre_parse.py:138(__len__)
       16    0.000    0.000    0.000    0.000 sre_parse.py:142(__getitem__)
       11    0.000    0.000    0.000    0.000 sre_parse.py:150(append)
# ...

حالا بیایید ببینیم چگونه می توانیم از آن به عنوان ابزار خط فرمان استفاده کنیم. فرض کنید اسکریپت زیر را داریم:

def calculate_factorial(n):
    if n == 1:
        return 1
    else:
        return n * calculate_factorial(n-1)

def main():
    print(calculate_factorial(10))

if __name__ == "__main__":
    main()

برای پروفایل این اسکریپت می توانید از cProfile ماژول از خط فرمان به شرح زیر است:

$ python -m cProfile script.py

خروجی نشان می دهد که هر تابع چند بار فراخوانی شده است، چقدر زمان برای هر تابع صرف شده است و سایر اطلاعات مفید.

با استفاده از Line Profiler

در حالی که cProfile اطلاعات مفیدی را ارائه می دهد، اگر بخواهید خط به خط کد خود را نمایه کنید، ممکن است کافی نباشد. اینجاست که line_profiler ابزار به کار می آید این یک ابزار خارجی است که آمار پروفایل گذاری خط به خط را برای برنامه های پایتون شما ارائه می دهد.

ابتدا باید آن را با استفاده از آن نصب کنید pip:

$ pip install line_profiler

استفاده کنیم line_profiler برای نمایه کردن همان اسکریپت که قبلا استفاده کردیم. برای انجام این کار، باید یک دکوراتور به عملکردی که می خواهید نمایه کنید اضافه کنید:

from line_profiler import LineProfiler

def profile(func):
    profiler = LineProfiler()
    profiler.add_function(func)
    return profiler(func)

@profile
def calculate_factorial(n):
    if n == 1:
        return 1
    else:
        return n * calculate_factorial(n-1)

def main():
    print(calculate_factorial(10))

if __name__ == "__main__":
    main()

حال، اگر اسکریپت خود را اجرا کنید، line_profiler خروجی آمار برای هر خط در calculate_factorial تابع.

به یاد داشته باشید که از @profile دکوراتور به مقدار کم، زیرا می تواند به طور قابل توجهی کد شما را کاهش دهد.

نمایه سازی بخش مهمی از بهینه سازی اسکریپت های پایتون شما است. این به شما کمک می کند تا گلوگاه ها و بخش های ناکارآمد کد خود را شناسایی کنید. با ابزارهایی مانند cProfile و line_profiler، می توانید آمار دقیقی از اجرای کد خود بدست آورید و از این اطلاعات برای بهینه سازی آن استفاده کنید.

تفسیر نتایج پروفایل

پس از اجرای یک ابزار پروفایل بر روی اسکریپت پایتون، جدولی از نتایج به شما نمایش داده می شود. اما این اعداد به چه معناست؟ چگونه می توانید آنها را درک کنید؟ بیایید آن را تجزیه کنیم.

جدول نتایج معمولاً شامل ستون هایی مانند ncalls برای تعداد تماس ها، tottime برای کل زمان صرف شده در تابع داده شده به استثنای فراخوانی به توابع فرعی، percall با اشاره به ضریب tottime تقسیم بر ncalls، cumtime برای زمان تجمعی صرف شده در این و همه تابع‌های فرعی، و filename:lineno(function) ارائه داده های مربوط به هر تابع.

در اینجا یک نمونه خروجی از cProfile:

         5 function calls in 0.000 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    0.000    0.000 <ipython-input-1-9e8e3c5c3b72>:1(<module>)
        1    0.000    0.000    0.000    0.000 {built-in method builtins.exec}
        1    0.000    0.000    0.000    0.000 {built-in method builtins.len}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}

این tottime و cumtime ستون‌ها از اهمیت ویژه‌ای برخوردار هستند زیرا به شناسایی بخش‌هایی از کد شما کمک می‌کنند که بیشترین زمان را مصرف می‌کنند.

توجه داشته باشید: خروجی بر اساس نام تابع مرتب می شود، اما شما می توانید آن را با هر ستون دیگری با عبور از آن مرتب کنید sort پارامتر به print_stats روش. مثلا، p.print_stats(sort='cumtime') خروجی را بر اساس زمان تجمعی مرتب می کند.

پیشنهاد می‌کنیم بخوانید:  استفاده از Spies برای تست در جاوا اسکریپت با تست نرم افزار Sinon.jsIn، یک «جاسوسی» روش استفاده از یک تابع را هنگام آزمایش ثبت می کند. این شامل چند بار فراخوانی شده، اینکه آیا با آرگومان های صحیح فراخوانی شده است یا خیر، و چه چیزی برگردانده شده است. در حالی که تست ها در درجه اول برای تایید خروجی یک تابع استفاده می شوند، گاهی اوقات ...

تکنیک های بهینه سازی بر اساس نتایج پروفایل

هنگامی که گلوگاه های کد خود را شناسایی کردید، گام بعدی بهینه سازی آنهاست. در اینجا چند تکنیک کلی وجود دارد که می توانید از آنها استفاده کنید:

  • از محاسبات غیر ضروری خودداری کنید: اگر نتایج نمایه‌سازی شما نشان می‌دهد که یک تابع چندین بار با آرگومان‌های یکسان فراخوانی می‌شود، از تکنیک‌های حافظه‌سازی برای ذخیره و استفاده مجدد از نتایج فراخوانی‌های تابع گران قیمت استفاده کنید.

  • از توابع و کتابخانه های داخلی استفاده کنید: توابع و کتابخانه های داخلی پایتون معمولاً برای عملکرد بهینه شده اند. اگر متوجه شدید که کد سفارشی شما کند است، ببینید آیا یک تابع یا کتابخانه داخلی وجود دارد که می تواند کار را سریعتر انجام دهد.

  • بهینه سازی ساختارهای داده: انتخاب ساختار داده تا حد زیادی می تواند بر عملکرد تاثیر بگذارد. به عنوان مثال، اگر کد شما زمان زیادی را صرف جستجوی موارد در یک لیست می کند، به جای آن از یک مجموعه یا دیکشنری استفاده کنید که می تواند این کار را بسیار سریعتر انجام دهد.

بیایید مثالی ببینیم که چگونه می توانیم تابعی را که دنباله فیبوناچی را محاسبه می کند بهینه کنیم. کد اصلی اینجاست:

def fib(n):
    if n <= 1:
       return n
    else:
       return(fib(n-1) + fib(n-2))

اجرای پروفایلر روی این کد نشان می دهد که fib تابع چندین بار با آرگومان های یکسان فراخوانی می شود. ما می‌توانیم این را با استفاده از تکنیکی به نام حافظه‌سازی بهینه کنیم، که نتایج فراخوانی‌های عملکرد گران قیمت را ذخیره می‌کند و در صورت نیاز مجدداً از آنها استفاده می‌کند:

def fib(n, memo={}):
    if n <= 1:
       return n
    else:
       if n not in memo:
           memo(n) = fib(n-1) + fib(n-2)
       return memo(n)

با این بهینه سازی ها، fib عملکرد اکنون به طور قابل توجهی سریعتر است و نتایج نمایه سازی این بهبود را منعکس می کند.

به یاد داشته باشید، کلید کد کارآمد این نیست که همه چیز را بهینه کنید، بلکه تمرکز بر روی بخش هایی است که واقعاً در آنها اهمیت دارد – تنگناها. نمایه سازی به شما کمک می کند تا این تنگناها را شناسایی کنید، بنابراین می توانید تلاش های بهینه سازی خود را در جایی صرف کنید که بیشترین تفاوت را ایجاد کنند.

نتیجه

پس از خواندن این مقاله، باید درک خوبی از روش ایجاد نمایه یک اسکریپت پایتون داشته باشید. ما بحث کرده ایم که پروفایل چیست و چرا برای بهینه سازی کد شما بسیار مهم است. ما همچنین شما را با چند ابزار نمایه سازی پایتون آشنا کرده ایم cProfile، یک نمایه ساز داخلی پایتون و Line Profiler، یک ابزار پروفایل پیشرفته.

ما روش استفاده از این ابزارها برای نمایه کردن اسکریپت پایتون و روش تفسیر نتایج را توضیح داده ایم. بر اساس این نتایج، چند تکنیک بهینه سازی را یاد گرفته اید که می تواند به شما در بهبود عملکرد کدتان کمک کند.

فقط به یاد داشته باشید که پروفایل ابزار قدرتمندی است، اما یک گلوله نقره ای نیست. این می تواند به شما در شناسایی تنگناها و کدهای ناکارآمد کمک کند، اما این به شما بستگی دارد که راه حل های آن را بیابید.

در تجربه من، زمان صرف شده برای یادگیری و به کارگیری تکنیک های نمایه سازی همیشه در دراز مدت نتیجه داده است. نه تنها منجر به کدهای کارآمدتر می شود، بلکه به شما کمک می کند تا به یک برنامه نویس ماهر و آگاه در پایتون تبدیل شوید.

(برچسب‌ها به ترجمه)# python



منتشر شده در 1402-12-28 04:19:05

امتیاز شما به این مطلب
دیدگاه شما در خصوص مطلب چیست ؟

آدرس ایمیل شما منتشر نخواهد شد.

لطفا دیدگاه خود را با احترام به دیدگاه های دیگران و با توجه به محتوای مطلب درج کنید