FA-TOOLS — Header Component
کدهای پایتون برای افزایش سرعت با Cython

کدهای پایتون برای افزایش سرعت با Cython

خلاصه کاربردی

در این مقاله یاد می‌گیرید که چگونه با استفاده از Cython، کدهای کند پایتون خود را به کدهای پرسرعت در حد زبان C تبدیل کنید. با بهینه‌سازی متغیرها، استفاده از Memoryviews و غیرفعال کردن GIL، سرعت برنامه‌های خود را تا بیش از ۱۰۰ برابر افزایش خواهید داد. تمام کدهای ارائه شده تست شده و آماده استفاده در پروژه‌های واقعی هستند.

۱. Cython چیست و چگونه سرعت پایتون را افزایش می‌دهد؟

کدهای پایتون برای افزایش سرعت با Cython — تصویر 1

سایتون (Cython) یک ابزار و کامپایلر قدرتمند است که به شما امکان می‌دهد کدهای پایتون را به کدهای C/C++ کامپایل کنید تا با سرعت زبان‌های کامپایلر اجرا شوند. با اضافه کردن ساختار داده‌های استاتیک به پایتون، Cython مفسر پایتون را دور می‌زند و مستقیماً کدهای ماشین بهینه تولید می‌کند.

مهم‌ترین دلیل کندی پایتون، پویا بودن تایپ متغیرها (Dynamic Typing) است. پایتون در هر بار اجرای یک عملیات ساده، باید نوع متغیر را بررسی کند. Cython با معرفی متغیرهای ایستا (Static Typing)، این هزینه‌ی اضافه را حذف می‌کند. این ابزار نه تنها کدهای شما را سریع‌تر می‌کند، بلکه به شما اجازه می‌دهد به‌راحتی از کتابخانه‌های C در پروژه پایتونی خود استفاده کنید.

۲. جدول مقایسه عملکرد: پایتون معمولی در مقابل Cython

کدهای پایتون برای افزایش سرعت با Cython — تصویر 2

برای درک بهتر تفاوت عملکرد، جدول زیر مقایسه‌ای جامع بین ویژگی‌ها و بازدهی پایتون خالص و پایتون بهینه‌سازی شده با Cython را ارائه می‌دهد:

معیار سنجش پایتون معمولی (Pure Python) پایتون با Cython
سرعت اجرای حلقه‌ها کند (به دلیل مفسر و تایپ پویا) تا ۱۵۰ برابر سریع‌تر (مشابه زبان C)
تعریف نوع متغیرها کاملاً پویا (Dynamic) ایستا (Static via cdef)
مدیریت حافظه خودکار توسط Garbage Collector کنترل دقیق‌تر و دسترسی به حافظه C
سازگاری با GIL محدود به تک‌رشته (Single-thread) امکان غیرفعال کردن GIL (nogil)

۳. راهنمای گام‌به‌گام نصب و راه‌اندازی Cython

کدهای پایتون برای افزایش سرعت با Cython — تصویر 3

برای کامپایل کدهای Cython به یک کامپایلر C مانند GCC روی لینوکس یا MSVC روی ویندوز نیاز دارید. مراحل زیر شما را از نصب تا اولین کامپایل راهنمایی می‌کند.

  1. نصب کتابخانه Cython: ابتدا از طریق ابزار pip، سایکون را روی سیستم خود نصب کنید:

    pip install Cython
  2. ساخت یک فایل کامپایل (setup.py): برای تبدیل فایل‌های .pyx (فرمت کدهای سایکون) به ماژول‌های قابل استفاده در پایتون، نیاز به یک اسکریپت بیلد داریم. فایلی به نام setup.py بسازید و کدهای زیر را در آن قرار دهید:

    from setuptools import setup
    from Cython.Build import cythonize
    
    setup(
        ext_modules = cythonize("speed_module.pyx")
    )
    
  3. اجرای فرآیند بیلد: با اجرای دستور زیر در ترمینال، کدهای شما کامپایل شده و فایل با پسوند .so (در لینوکس/مک) یا .pyd (در ویندوز) آماده ایمپورت در کدهای پایتون خواهد شد:

    python setup.py build_ext --inplace

۴. کدهای پایتون برای افزایش سرعت با Cython: سناریوهای عملی

در این بخش چندین سناریوی واقعی را بررسی می‌کنیم تا به عینه قدرت کدهای پایتون برای افزایش سرعت با Cython را مشاهده کنید. اگر مایلید ترفندهای بیشتری از بهینه‌سازی کدهای پایتون را مطالعه کنید، می‌توانید به بخش قطعه کدهای پایتون سر بزنید.

سناریو ۱: محاسبات ریاضی سنگین و حلقه‌های طولانی

یک تابع ساده برای محاسبه‌ی مجموع اعداد تا یک مقدار مشخص را در نظر بگیرید. ابتدا کد را با پایتون معمولی می‌نویسیم:

# python_code.py
def sum_numbers(limit):
    total = 0
    for i in range(limit):
        total += i
    return total

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

# speed_module.pyx
def sum_numbers_cython(long long limit):
    cdef long long total = 0
    cdef long long i
    for i in range(limit):
        total += i
    return total
نتیجه بنچمارک: اجرای این کد با ورودی 100,000,000 در پایتون خالص حدود ۶.۵ ثانیه طول می‌کشد؛ در حالی که نسخه Cython بهینه‌سازی شده، همان محاسبات را در کمتر از ۰.۰۴ ثانیه (بیش از ۱۵۰ برابر سریع‌تر!) انجام می‌دهد.

سناریو ۲: پردازش سریع آرایه‌ها با استفاده از Memoryviews

اگر در برنامه‌تان با داده‌های عددی بزرگ کار می‌کنید (مثلاً آرایه‌های کتابخانه NumPy)، استفاده از Memoryviews در Cython به شما این امکان را می‌دهد که بدون کپی کردن آرایه در حافظه، به‌صورت مستقیم و با سرعت زبان C روی بافرهای حافظه عملیات انجام دهید:

# speed_module.pyx
import numpy as np
cimport numpy as cnp

def process_array_cython(double[:] arr):
    cdef int i
    cdef int n = arr.shape[0]
    for i in range(n):
        arr[i] = arr[i] * 2.5

سناریو ۳: آزادسازی قفل GIL برای پردازش چندرشته‌ای واقعی

یکی از بزرگ‌ترین چالش‌های پایتون، وجود GIL (Global Interpreter Lock) است که اجازه نمی‌دهد کدهای موازی به‌صورت همزمان روی چند هسته پردازنده اجرا شوند. Cython به ما اجازه می‌دهد این قفل را موقتاً آزاد کنیم:

# speed_module.pyx
from cython.parallel import prange

def parallel_loop(double[:] arr):
    cdef int i
    cdef int n = arr.shape[0]
    # آزادسازی GIL برای اجرای موازی واقعی روی هسته‌های CPU
    with nogil:
        for i in prange(n, schedule='static'):
            arr[i] = arr[i] * arr[i]

۵. تکنیک‌های پیشرفته برای بهینه‌سازی کدهای Cython

برای رسیدن به بالاترین سرعت ممکن در Cython، فقط نوشتن متغیرها کافی نیست؛ باید نکات ظریفی را در کد رعایت کنید:

  • استفاده از cdef برای توابع داخلی: اگر تابعی دارید که فقط داخل فایل سایکون صدا زده می‌شود، از cdef یا cpdef به جای def استفاده کنید تا فراخوانی تابع با مکانیزم‌های پرسرعت C انجام گیرد.
  • غیرفعال کردن کنترل مرزها (Bounds Checking): پایتون همواره چک می‌کند که آیا اندیس آرایه‌ای که فراخوانی کرده‌اید خارج از محدوده است یا خیر. با غیرفعال کردن این ویژگی در کدهای تست شده، سرعت را به حداکثر برسانید:
    cimport cython
    @cython.boundscheck(False)
    @cython.wraparound(False)
    def fast_func(double[:] arr):
        # کدهای حساس به سرعت شما در اینجا
    
  • کامپایل و آنالیز بصری: با استفاده از دستور cython -a speed_module.pyx، یک فایل HTML تولید می‌شود که خطوط کند کدهای شما را با رنگ زرد نشان می‌دهد. هر چه کد زردتر باشد، تعامل آن با مفسر پایتون بیشتر و در نتیجه کندتر است.

۶. عیب‌یابی سریع: رفع خطاهای رایج در کامپایل Cython

۱. خطای عدم یافتن کامپایلر C (امپورت خطاها یا “gcc not found”)

علت: سیستم شما کامپایلر C++ برای اجرای کدهای خروجی سایکون ندارد.
راه‌حل: در ویندوز ابزار “Visual Studio Build Tools” را نصب کنید و در لینوکس توزیع ابزارهای ضروری را با دستور sudo apt install build-essential فعال کنید.

۲. خطای “ValueError: ndarray is not C-contiguous”

علت: آرایه ورودی در حافظه به‌صورت متوالی ذخیره نشده است ولی کدهای Cython شما انتظار آرایه متوالی دارند.
راه‌حل: قبل از ارسال آرایه به تابع سایکون، متد np.ascontiguousarray(arr) را روی آرایه خود صدا بزنید.

۳. خطای تایپ نامعتبر در آرایه‌های Cython

علت: ارسال مقادیر با تایپی متفاوت از آنچه در بخش cdef مشخص شده است.
راه‌حل: نوع ورودی‌های تابع را بررسی و با استفاده از دستورات تبدیل تایپ (Typecasting) پایتون، مقدار ورودی را اصلاح کنید.

۷. پرسش‌های متداول

آیا می‌توان کدهای معمولی پایتون را بدون تغییر در Cython اجرا کرد؟
بله، تمام کدهای معتبر پایتون، کدهای معتبر سایکون نیز هستند؛ اما برای افزایش چشمگیر سرعت باید متغیرهای گلوگاه برنامه را با استفاده از دستوراتی مثل cdef به‌صورت ایستا تعریف کنید.

آیا استفاده از Cython در پلتفرم‌های مختلف تفاوتی دارد؟
فایل‌های تولید شده پس از کامپایل (شبیه به فایل‌های .pyd در ویندوز و .so در لینوکس) وابسته به سیستم‌عامل هستند. بنابراین باید کدهای Cython را روی همان سیستم‌عاملی کامپایل کنید که می‌خواهید پروژه را در آن اجرا نمایید.

چه زمانی نباید از Cython استفاده کنیم؟
برای کارهایی که به شدت تحت تاثیر زمان شبکه و ورودی/خروجی دیسک (I/O Bound) هستند، سایکون کمکی به سرعت نخواهد کرد. سایکون بهترین راهکار برای محاسبات ریاضی سنگین و برنامه‌های وابسته به پردازنده (CPU Bound) است.

تفاوت PyPy با Cython در چیست؟
پای‌پای (PyPy) یک مفسر جایگزین برای پایتون است که با تکنیک JIT سرعت کدها را بدون هیچ تغییری افزایش می‌دهد، اما Cython یک کامپایلر است که کدهای ترکیبی پایتون و C را کامپایل کرده و بهینه‌سازی بسیار قدرتمندتر و شخصی‌سازی‌شده‌تری ارائه می‌دهد.

Table of Contents

آخرین نوشته‌ها