برنامه نویسی

بهینه سازی کد پایتون با استفاده از cProfile و ماژول PyPy: یک راهنمای کامل

مقدمه

به‌عنوان توسعه‌دهندگان پایتون، قبل از اینکه نگران بهینه‌سازی کد خود باشیم، اغلب بر روی کارکردن کد خود تمرکز می‌کنیم. با این حال، هنگامی که با برنامه های کاربردی در مقیاس بزرگ یا کدهای عملکرد حیاتی سروکار دارید، بهینه سازی بسیار مهم می شود. در این پست، دو ابزار قدرتمندی را که می‌توانید برای بهینه‌سازی کد پایتون خود استفاده کنید، پوشش خواهیم داد: cProfile ماژول و مفسر PyPy.

در پایان این پست، یاد خواهید گرفت:

  1. نحوه شناسایی تنگناهای عملکرد با استفاده از cProfile ماژول
  2. چگونه کد خود را برای سرعت بهینه کنیم
  3. نحوه استفاده از PyPy برای تسریع بیشتر برنامه های پایتون با کامپایل Just-in-Time (JIT).

چرا بهینه سازی عملکرد مهم است

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

بهینه سازی معمولاً این مراحل را دنبال می کند:

  1. کد خود را نمایه کنید تا بفهمیم تنگناها کجاست
  2. کد را بهینه کنید در زمینه هایی که ناکارآمد هستند.
  3. کد بهینه شده را اجرا کنید در یک مفسر سریعتر، مانند PyPy، برای دستیابی به حداکثر کارایی.

حالا بیایید با پروفایل کد شما شروع کنیم.

مرحله 1: پروفایل کد خود را با cProfile

چیست cProfile?

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

با استفاده از cProfile از خط فرمان

ساده ترین راه برای ایجاد نمایه یک اسکریپت اجرای آن است cProfile از خط فرمان به عنوان مثال، فرض کنید یک اسکریپت به نام دارید my_script.py:

python -m cProfile -s cumulative my_script.py
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

توضیح:

  • -m cProfile: اجرا می کند cProfile ماژول به عنوان بخشی از کتابخانه استاندارد پایتون.
  • -s cumulative: نتایج پروفایل را بر اساس زمان تجمعی صرف شده در هر تابع مرتب می کند.
  • my_script.py: اسکریپت پایتون شما.

این یک تفکیک دقیق از جایی که کد شما زمان خود را صرف می کند ایجاد می کند.

مثال: پروفایل یک اسکریپت پایتون

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

def fibonacci(n):
    if n  1:
        return n
    return fibonacci(n-1) + fibonacci(n-2)

if __name__ == "__main__":
    print(fibonacci(30))
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

اجرای این اسکریپت با cProfile:

python -m cProfile -s cumulative fibonacci_script.py
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

درک کردن cProfile خروجی

یک بار که می دوید cProfile، چیزی شبیه به این را خواهید دید:

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
     8320    0.050    0.000    0.124    0.000 fibonacci_script.py:3(fibonacci)
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

هر ستون داده های کلیدی عملکرد را ارائه می دهد:

  • تماس می گیرد: تعداد دفعاتی که تابع فراخوانی شده است.
  • تایم: کل زمان صرف شده در تابع (به استثنای توابع فرعی).
  • cumtime: زمان تجمعی صرف شده در تابع (از جمله توابع فرعی).
  • صدا زدن: زمان هر تماس

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

نمایه سازی بخش های خاص کد شما

همچنین می توانید استفاده کنید cProfile اگر فقط می‌خواهید بخش‌های خاصی را نمایه کنید، به صورت برنامه‌نویسی در کد خود قرار دهید.

import cProfile

def fibonacci(n):
    if n  1:
        return n
    return fibonacci(n-1) + fibonacci(n-2)

if __name__ == "__main__":
    cProfile.run('fibonacci(30)')
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

مرحله 2: بهینه سازی کد پایتون

هنگامی که با استفاده از گلوگاه های کد خود را شناسایی کردید cProfile، زمان بهینه سازی فرا رسیده است.

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

  1. از توابع داخلی استفاده کنید: توابع داخلی مانند sum()، min()، و max() در پایتون بسیار بهینه شده اند و معمولا سریعتر از حلقه های پیاده سازی دستی هستند.

مثال:

   # Before: Custom sum loop
   total = 0
   for i in range(1000000):
       total += i

   # After: Using built-in sum
   total = sum(range(1000000))
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

  1. از تماس های کاربردی غیر ضروری خودداری کنید: فراخوانی های تابع دارای سربار هستند، به خصوص حلقه های داخلی. سعی کنید تماس های اضافی را کاهش دهید.

مثال:

   # Before: Unnecessary repeated calculations
   for i in range(1000):
       print(len(my_list))  # len() is called 1000 times

   # After: Compute once and reuse
   list_len = len(my_list)
   for i in range(1000):
       print(list_len)
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

  1. حفظ کردن: برای توابع بازگشتی، می توانید از حافظه گذاری برای ذخیره نتایج محاسبات گران قیمت استفاده کنید تا از تکرار کار جلوگیری کنید.

مثال:

   from functools import lru_cache

   @lru_cache(maxsize=None)
   def fibonacci(n):
       if n  1:
           return n
       return fibonacci(n-1) + fibonacci(n-2)
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

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

مرحله 3: استفاده از PyPy برای کامپایل سازی به موقع

PyPy چیست؟

PyPy یک مفسر جایگزین پایتون است که از کامپایل Just-in-Time (JIT) برای سرعت بخشیدن به کد پایتون شما استفاده می کند. PyPy مسیرهای کد اغلب اجرا شده را در کد ماشین کامپایل می کند و آن را بسیار سریعتر از مفسر استاندارد CPython برای کارهای خاص می کند.

در حال نصب PyPy

می توانید PyPy را با استفاده از یک مدیریت بسته مانند نصب کنید apt در لینوکس یا brew در macOS:

# On Ubuntu
sudo apt-get install pypy3

# On macOS (using Homebrew)
brew install pypy3
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

اجرای کد پایتون با PyPy

هنگامی که PyPy نصب شد، می توانید اسکریپت خود را به جای CPython با آن اجرا کنید:

pypy3 my_script.py
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

چرا از PyPy استفاده کنیم؟

  • PyPy ایده آل برای وظایف محدود به CPU جایی که برنامه بیشتر زمان خود را در محاسبات صرف می کند (به عنوان مثال، حلقه ها، توابع بازگشتی، اعداد خرد کردن).
  • کامپایلر JIT PyPy مسیرهای کدی که اغلب اجرا می شوند را بهینه می کند، که می تواند منجر به افزایش سرعت قابل توجه بدون تغییر کد شود.

مرحله 4: ترکیب کردن cProfile و PyPy برای حداکثر بهینه سازی

اکنون بیایید این ابزارها را برای بهینه سازی کامل کد پایتون خود ترکیب کنیم.

نمونه گردش کار

  1. کد خود را نمایه کنید با استفاده از cProfile برای شناسایی تنگناها
  2. کد خود را بهینه کنید با استفاده از تکنیک‌هایی که در مورد آن بحث کردیم (توکار، حافظه‌گذاری، اجتناب از فراخوانی‌های غیرضروری توابع).
  3. کد بهینه شده خود را اجرا کنید با PyPy برای دستیابی به بهبود عملکرد بیشتر.

بیایید مثال فیبوناچی خود را دوباره مرور کنیم و همه چیز را کنار هم بگذاریم.

from functools import lru_cache

@lru_cache(maxsize=None)
def fibonacci(n):
    if n  1:
        return n
    return fibonacci(n-1) + fibonacci(n-2)

if __name__ == "__main__":
    import cProfile
    cProfile.run('print(fibonacci(30))')
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

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

pypy3 fibonacci_script.py
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

نتیجه گیری

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

به طور خلاصه:

  1. کد خود را با cProfile برای درک تنگناهای عملکرد
  2. از تکنیک‌های بهینه‌سازی پایتون، مانند استفاده از داخلی‌ها و حافظه‌سازی استفاده کنید.
  3. برای دستیابی به عملکرد بهتر، کد بهینه شده را روی PyPy اجرا کنید.

با این رویکرد، می‌توانید برنامه‌های پایتون خود را سریع‌تر و کارآمدتر اجرا کنید، مخصوصاً برای کارهای محدود به CPU.

با من ارتباط برقرار کنید:
Github
لینکدین

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا