12 تکنیک حرفه ای برای افزایش سرعت پایتون!

تکنیک های بهینه سازی عملکرد در پایتون
پایتون یکی از زبان های برنامه نویسی هست که در سال های اخیر به شدت رشد داشته و توسعه دهندگان و کارآموزان زیادی را به سمت خود کشیده هست!
پایتون امروزه به عنوان یکی از محبوب ترین و پرکاربرد ترین زبان های برنامه نویسی در جهان شناخته می شود که بخاطر سادگی یادگیری، نزدیک بودن به زبان انسان، جامعه کاربری بسیار بزرگ و کتابخانه های متنوع توسعه دهندگان و شرکت های بزرگی را به سمت خود کشانده هست و امروزه طیف وسیعی از پروژه های بزرگ در بخش های مختلفی از پروژه خود از پایتون استفاده می کنند به عبارت دیگر پروژه ی بزرگی در دنیا نیست که ردپایی از پایتون در آن مشاهده نشود!
پایتون امروز دیگر تنها یک زبان مناسب برای یادگیری برنامه نویسی نیست بلکه یکی از ستون های اصلی بسیاری از فناوری های جدید و به روز دنیا محسوب می شود از توسعه وب گرفته تا ساخت API ها و ترند این روز های دنیا یعنی هوش مصنوعی!
کاربرد های پایتون فقط به همین موارد خلاصه نمی شود و یادگیری ماشین، علم داده، اتوماسیون، تحلیل داده های حجیم و پردازش های ابری و حتی امنیت سایبری همگی از حوزه هایی هستند که پایتون در آن ها نقش عمده را دارد!
هیچ وقت محبوبیت و جامعه آماری بزرگ یک زبان برنامه نویسی را نمی توان امری اتفاقی دانست! شرکت های بزرگی مانند گوگل، نتفلیکس، اسپاتیفای، اینستاگرام، اوبر و ناسا در بخش های مختلف زیرساخت و سرویس های خود از پایتون استفاده می کنند و این شرکت ها تنها شرکت های بزرگ دنیا نیستند که بخش هایی از پروژه خود را بر مبنای پایتون بنا کردند!
توسعه دهندگان وقتی میزان استفاده پایتون را در پروژه های مختلف و بزرگ مشاهده کردند طبیعی هست که به سمت یادگیری این زبان آمدند و تقاضا برای یادگیری و آموزش این زبان طی سال های اخیر با سرعت چشم گیری رشد داشته است!
یکی از مهم ترین مزایایی که پایتون دارد سرعت بالای توسعه نرم افزار هست! توسعه دهندگان می توانند با نوشتن کد کمتر، پروژه های پیچیده تری را در زمان کوتاه پیاده سازی کنند و همچنین وجود کتابخانه های فراوانی که این زبان دارد فرآیند توسعه را خیلی ساده تر کرده است!
برخی از مهم ترین مزایای زبان پایتون عبارتند از:
سادگی و خوانایی بالای کد ها
یادگیری آسان برای افراد مبتدی
وجود بسیار گسترده کتابخانه ها و فریم ورک ها
پشتیبانی قوی از هوش مصنوعی و یادگیری ماشین
قابلیت اجرا روی سیستم عامل های مختلف
جامعه کاربری بزرگ و مستندات فراوان
توسعه سریع تر پروژه ها نسبت به بسیاری از زبان های برنامه نویسی
همانطور که گفته شد پایتون از نظر مزایا بسیار زبان برنامه نویسی خوب و قدرتمندی هست و نزدیک بودن آن به زبان انسان کار را برای توسعه دهندگان ساده تر هم کرده است! اما با وجود تمام موارد مثبتی که در خصوص پایتون ذکر شد یک نقطه ضعف مهم دارد و آن عملکرد یا همان Performance می باشد!
پایتون یک زبان مفسری یا Interpreted Language محسوب می شود و در بسیاری از سناریو ها، به ویژه پردازش های سنگین، سرعت اجرای آن نسبت به زبان هایی مانند C، C++ یا Go کمتر است!
این موضوع شاید در ابتدای راه اندازی پروژه خیلی به چشم نیاید و این کم بودن سرعت خودش را نشان ندهد اما وقتی کم کم پروژه بزرگ تر می شود و کاربران زیادی وارد پروژه می شوند و پردازش حجم زیادی از داده ها اتفاق می افتد می تواند کم کم به یک معضل جدی تبدیل شود! اجرای همزمان درخواست های متعددد و رشد پیچیدگی نرم افزار باعث کندی شدید پروژه های پایتونی خواهد شد!
البته این نکته به این معنا نیست که قرار است پروژه های بزرگ پایتونی کند باشند! خوشبختانه پایتون ابزرها و تکنیک های زیادی را برای بهینه سازی عملکرد در اختیار توسعه دهنده قرار می دهد و با استفاده از این روش ها می توان مصرف حافظه و منابع سخت افزاری سیستم را کاهش داد و سرعت اجرای برنامه را تا حد بسیار زیادی بالا برد که باعث افزایش بهره وری نرم افزار هم می شود!
چرا بهینه سازی در پروژه های بزرگ پایتون اهمیت دارد؟
در ابتدای مسیر توسعه نرم افزار بسیاری از پروژه های پایتون با حجم داده کم و تعداد کاربران محدود اجرا می شوند و هیچ پروژه ای نیست که در زمان انتشار یک شبه به چند صد هزار کاربر برسد! معمولا در این شرایط هیچ مشکلی از نظر عملکرد دیده نمی شود و پروژه به شکل کاملا ایده آل به خدمت رسانی مشغول می باشد.
با رشد پروژه و تعداد کاربران بالا چالش های جدی کم کم شروع به نمایان شدن می کنند!
در پروژه های بزرگ هر میلی ثانیه تاخیر می تواند تاثیر مستقیمی بر تجربه کاربران، هزینه های زیرساخت و پایداری سرویس داشته باشد! هیچ وقت در خصوص کند شدن پروژه ها به چند ثانیه فکر نکنید! صحبت سر چند میلی ثانیه هست که باید یک پروژه در سطح جهانی آن را رعایت کند و از کندی اجتناب کند! به همین دلیل بهینه سازی عملکرد دیگر یک گزینه انتخابی و اختیاری نیست بلکه به یکی از بخش های ضروری توسعه نرم افزار تبدیل می شود!
پایتون همانطور که گفته شد بخاطر مفسری بودن و برخی محدودیت های ذاتی که دارد در صورت عدم رعایت اصول بهینه سازی ممکن است با مشکلات زیادی رو به رو شود و این مشکلات زمانی بیشتر می شود که برنامه با حجم بالایی از درخواست ها یا داده ها سر و کار داشته باشد!
برخی از رایج ترین مشکلاتی که در پروژه های بزرگ پایتون مشاهده می شود عبارتند از:
افزایش زمان پاسخگویی API ها
افزایش مصرف CPU و حافظه سرور
کاهش سرعت پردازش داده ها
کاهش مقیاس پذیری نرم افزار
افزایش هزینه های زیرساخت و سرورها
اگر بخواهیم با یک مثال این مورد را توضیح دهیم باید بگوییم فرض کنید یک فروشگاه اینترنتی با استفاده از پایتون توسعه داده شده است و در ابتدای کاربر روزانه تنها چند صد کاربر از آن استفاده می کنند و همه چیز به خوبی اجرا می شود و سرعت خوبی پروژه دارد.
اما وقتی این کسب و کار رشد می کند افزایش کاربران به چند ده هزار نفر می رسد اجرای کوئری های غیربهینه، پردازش های تکراری و مصرف بالای حافظه می تواند باعث کند شدن کل سیستم شود.
همین مورد در سرویس هایی که مبتنی بر هوش مصنوعی، سیستم های تحلیل داده، وب سایت های پرترافیک و میکروسرویس ها هم مشاهده می شوند هر چه حجم داده ها و تعداد درخواست ها بیشتر شود اهمیت بهینه سازی هم بیشتر خودش را نمایش می دهد!
بسیاری از شرکت ها به جای افزایش مداوم منابع سخت افزاری، ابتدا سعی می کنند نرم افزار خود را بهینه کنند. در بسیاری از مواقع، تنها با اعمال چند تکنیک ساده می توان بدون نیاز به ارتقای سرورها، عملکرد برنامه را به شکل قابل توجهی بهبود داد.
به همین دلیل، توسعه دهندگان حرفه ای معمولا از همان ابتدای طراحی نرم افزار، به مقیاس پذیری و بهینه سازی عملکرد توجه ویژه ای دارند.
در ادامه این مقاله با مهم ترین تکنیک های بهینه سازی عملکرد در پایتون آشنا می شویم که به شما کمک می کنند سرعت اجرای برنامه ها را افزایش دهید، مصرف منابع را کاهش دهید و نرم افزار های پایدارتر و مقیاس پذیرتری توسعه دهید.
1- Profiling قبل از هرگونه بهینه سازی در پایتون:
یکی از مواردی که بسیاری از توسعه دهندگان انجام می دهند که خیلی اصولی نیست اینجاست که شروع به بهینه سازی می کنند قبل از اینکه اصلا بدانند معضل اصلی در کجاست!
در خیلی از زمان ها برنامه کند می شود و توسعه دهنده شروع به بهینه سازی می کند و حتی نمی داند اصلا علت این کندی چیست و با حدس و گمان اقداماتی را انجام می شود و شروع به بازنویسی کد می کند در صورتی که این روش نه تنها زمان توسعه را افزایش می دهد بلکه ممکن است باعث پیچیده تر شدن پروژه و بروز مشکلات دیگری هم شود!
بنابراین همیشه این نکته را به خاطر بسپارید که اولین قدم برای شروع بهینه سازی این است که در ابتدا بدانید مشکل کجاست و ابتدا شروع به Profiling کنید!
پروفایل گیری فرآيندی است که عملکرد بخش های مختلف برنامه را اندازه گیری می کند تا مشخص شود کدام قسمت بیشترین زمان اجرا یا بیشترین میزان مصرف حافظه و منابع سخت افزاری را دارد تا با آگاهی کامل و اعداد و ارقام بدانید مشکل دقیقا چیست!
به بیان ساده تر به جای حدس زدن ابزارهای پروفایل گیری به شما نشان می دهند دقیقا کدام تابع، حلقه یا عملیات باعث کندی برنامه شده است.
چرا Profiling اهمیت دارد؟
در پروژه های کوچک مشکلاتی که در عملکرد سیستم وجود دارد محسوس نیست و توسعه دهنده و کاربران کمی که وارد سایت می شوند مشکل خاصی را احساس نمی کنند اما در پروژه های بزرگ هر چند میلی ثانیه تاخیر هم تاثیر قابل توجهی بر عملکرد کلی سیستم دارد!
استفاده از Profiling مزایای متعددی دارد که از مهم ترین آن ها را می توان به موارد زیر اشاره کرد:
شناسایی دقیق علت مشکلات عملکردی
جلوگیری از بهینه سازی بخش های غیرضروری
کاهش مصرف منابع سخت افزاری
افزایش سرعت اجرای برنامه
بهبود مقیاس پذیری نرم افزار
کاهش هزینه های زیرساخت
پایتون برای تحلیل عمکرد برنامه ابزار های متعددی را در اختیار توسعه دهنده قرار می دهد که هر کدام کاربرد خاص خود را دارند!
هر کدام از این ابزار ها ویژگی ها خاص خود را دارد که به اختصار دو مورد را توضیح خواهیم داد.
مهم ترین ابزار های پروفایل گیری عبارتند از:
cProfile
line_profiler
py-spy
Scalene
اگر قصد دارید کار را از یک ابزار ساده و کاربردی شروع کنید، cProfile گزینه بسیار مناسبی خواهد بود.
استفاده از cProfile:
این ابزار که به صورت پیش فرض در پایتون وجود دارد و نیاز نیست که به صورت مجزا آن را نصب کنید به شما کمک زیادی خواهد کرد برای مثال فرض کنید تابع زیر را دارید:
import cProfile
def calculate_sum():
total = 0
for i in range(10000000):
total += i
return total
cProfile.run("calculate_sum()")
وقتی برنامه را اجرا کنید یک گزارش مشابه مورد زیر برای شما به نمایش گذاشته می شود.
4 function calls in 0.68 seconds
Ordered by: internal time
این گزارش نشان می دهد که اجرای تابع چه مقدار زمان مصرف کرده است و براساس زمان مصرف شده متوجه خواهید شد این تابع باعث ایجاد مشکلات عملکردی شده است یا خیر.
تحلیل دقیق تر با line_profiler:
اما گاهی اوقات نیاز است که زمان اجرای هر خط از کد را به صورت جداگانه بررسی کنیم در این شرایط می توان از ابزار line_profiler استفاده کرد!
برای استفاده از این ابزار ابتدا آن را باید نصب کنید چون یک کتابخانه مجزا می باشد و به صورت پیش فرض در پایتون فعال نمی باشد!
با دستور زیر می توان آن را نصب کرد:
pip install line_profiler
سپس تابع مورد نظر را مشخص کنید:
@profile
def process_data():
result = []
for i in range(1000000):
result.append(i * 2)
return result
برای اجرای تحلیل از دستورات زیر استفاده کنید:
kernprof -l script.py
python -m line_profiler script.py.lprof
Profiling تقریبا در تمام پروژه های حرفه ای کاربر دارد اما در بعضی شرایط بررسی این موضوع با اهمیت بیشتری همراه هست:
کند شدن API ها
افزایش زمان بارگذاری صفحات وب
پردازش حجم بالایی از داده ها
افزایش مصرف CPU
افزایش مصرف حافظه
اجرای طولانی تسک های پسزمینه
پروژه های مبتنی بر Django، Flask و FastAPI
خیلی از توسعه دهندگان تصور می کنند مشکل اصلی در حلقه ها یا الگوریتم های برنامه قرار دارد که باعث می شود سیستم به شدت کند شود یا مصرف منابع سخت افزاری با افزایش بالایی همراه باشد! اما این در حالی هست که در بسیاری از موارد مشکلات ایجاد شده عامل اصلی دیگری دارد برای مثال ممکن است علت اصلی کندی برنامه یکی از موارد زیر باشد:
کوئری های غیر بهینه دیتابیس
درخواست های متعدد به API های خارجی
بارگذاری فایل های حجیم
مصرف بیش از حد حافظه
عملیات تکراری و غیرضروری
به همین دلیل، قبل از اعمال هرگونه تغییر در کد، ابتدا باید محل دقیق مشکل مشخص شود.
اولین قانون در بهینه سازی عملکرد پایتون این است که هیچ وقت براساس حدس و گمان عمل نکنید و هزینه های بهینه سازی را برای خود زیاد نکنید! ابزار های گفته شده به شما کمک می کنند تصمیمات خود را بر پایه داده های واقعی بگیرید و زمان خود را صرف بهینه سازی بخش هایی که واقعا تاثیر مخرب چندانی ندارند تلف نکنید!
2- انتخاب Data Structures مناسب در پایتون:
یکی دیگر از ساده ترین و تاثیرگذارترین روش های بهینه سازی عملکرد در پایتون انتخاب ساختار داده مناسب می باشد! بسیاری از مشکلات مربوط به کندی برنامه ها به الگوریتم های پیچیده برنمیگردد بلکه به انتخاب اشتباه ساختار داده برمیگردد!
زبان برنامه نویسی پایتون ساختار داده های متنوعی دارد که در اختیار توسعه دهنده قرار می گیرد که هر کدام برای پروژه های خاصی با اهداف مشخصی طراحی شدند! استفاده نادرست از این ساختار ها می تواند باعث افزایش زمان پردازش، مصرف بیش از حد حافظه و کاهش عملکرد برنامه شود!
به عنوان مثال، بسیاری از برنامه نویسان به صورت پیش فرض از لیست List برای همه چیز استفاده می کنند، در حالی که در بسیاری از موارد، استفاده از Set یا Dictionary می تواند چندین برابر سریع تر باشد.
این مورد نکته بسیار مهمی هست که شما قبل از نوشتن هر بخشی از برنامه مشخص کنید که دقیقا قرار است چه عملیاتی روی داده ها انجام شود!
مهم ترین ساختار های داده در پایتون:
پایتون چند ساختار داده اصلی دارد که هر کدام کاربرد مخصوص به خود را دارند.
ساختار داده List:
List یکی از پرکاربرد ترین ساختار داده در پایتون هست و برای مجموعه از داده ها به صورت مرتب استفاده می شود.
در این ساختار داده ترتیب عناصر حفظ می شود و امکان تغییر عناصر و امکان وجود داده های تکراری هم وجود دارد.
مثال:
users = ["Ali", "Sara", "Reza"]
users.append("Nima")
print(users)
اما باید توجه داشته باشید که جستجو در لیست برای حجم بالای داده ها چندان بهینه نیست.
ساختار داده Set:
گاهی اوقات برای توسعه دهنده سرعت اهمیت بسیار ویژه ای دارد برای همین ساختار داده Set گزینه بسیار مناسبی هست این ساختار داده عناصر تکراری را حذف می کند و سرعت جستجو بسیار بالاست و ترتیب مشخصی هم ندارد.
مثال:
users = {"Ali", "Sara", "Reza"}
if "Sara" in users:
print("User exists")
ساختار داده Dictionary:
دیکشنری یکی از سریع ترین ساختار های داده پایتون محسوب می شود و برای نگهداری داده ها به صورت کلید و مقدار Key-Value استفاده می شود.
مثال:
user = {
"name": "Ali",
"age": 30
}
print(user["name"])
ساختار داده Tuple:
این ساختار داده کاملا شبیه به لیست هست با این تفاوت که پس از ایجاد امکان تغییر را نخواهد داشت!
مثال:
coordinates = (35.7, 51.4)
print(coordinates)
از آنجایی که تاپل ها غیرقابل تغییر هستند مصرف حافظه کمتری دارند و در برخی پروژه ها عملکرد بهتری هم از خود به نمایش می گذارند!
اشتباه رایج توسعه دهندگان پایتون استفاده پیش از اندازه از ساختار داده List می باشد! در بسیاری از پروژه ها توسعه دهنده بدون در نظر گرفتن نوع عملیات تمام داده ها را در این ساختار داده ذخیره می کند! در پروژه های کوچک شاید این موضوع اهمیت خاصی ندارد اما در پروژه های بزرگ و پردازش حجم بالای داده ها انتخاب اشتباه ساختار داده می تواند تاثیر مستقیمی بر عملکرد کل سیستم داده باشد!
گاهی اوقات تنها با جایگزین کردن یک List با Set یا Dictionary می توان سرعت اجرای بخشی از برنامه را چندین برابر افزایش داد، بدون اینکه نیاز به بازنویسی گسترده کد ها وجود داشته باشد.
3- کاهش هزینه حلقه ها و استفاده از NumPy :
حلقه ها یکی از پرکابردترین ابزرا ها در برنامه نویسی هستند و تقریبا در تمامی پروژه های پایتون مورد استفاده قرار می گیرند با این حال استفاده بیش از حد از حلقه ها روی حجم بالایی از داده ها می تواند به یکی از عواملی تبدیل شود که پروژه را کند خواهد کرد!
همانطور که در ابتدا اشاره شد پایتون بخاطر ذات مفسری که دارد در مقایسه با زبان های کامپایل شده مانند C و C++ سرعت اجرای کمتری دارد و زمانی این موضوع خود را نشان می دهد که میلیون ها بار یک عملیات تکراری درون حلقه اجرا می شود!
به همین دلیل است که یکی از مهم ترین روش های بهینه سازی عملکرد پروژه های پایتون کاهش وابستگی آن ها به حلقه های سنگین و استفاده از پردازش های برداری یا همان Vectorization می باشد!
Vectorization روشی هست که به جای پردازش تک به تک داده ها! مجموعه از داده ها را به صورت هم زمان پردازش می کند! این کار باعث می شود بسیاری از عملیات در سطح پایین تر و با سرعت بسیار بیشتری اجرا شوند!
یکی از بهترین و قدرتمندترین ابزار ها برای انجام این کار کتابخانه NumPy می باشد.
از مزایای استفاده از این کتابخانه :
افزایش قابل توجه سرعت پردازش داده ها
کاهش استفاده از حلقه های سنگین
مصرف بهینه تر حافظه
امکان انجام محاسبات پیچیده با کدنویسی کمتر
سازگاری با بسیاری از کتابخانه های دیگر
می توان اشاره کرد برای نصب این کتابخانه فقط کافی هست دستور زیر را اجرا کنید تا نصب شود.
pip install numpy
چرا حلقه های پایتونی کند هستند؟
هر بار که یک حلقه در پایتون اجرا می شود مفسر پایتون باید چند عملیات داخلی را مدیریت کند که شامل بررسی نوع داده، مدیریت حافظه و اجرای دستورات مختلف هست!
تا زمانی که تعداد تکرار ها کم باشد این موضوع هیچ مشکلی ایجاد نمی کند و چندان هم محسوس نیست اما زمانی که با میلیون ها داده سر و کار داشته باشید این هزینه محاسباتی به سرعت افزایش پیدا می کند.
به همین دلیل در پروژه های تحلیل داده، هوش مصنوعی و یادگیری ماشین و … استفاده از حلقه های سنتی توصیه و پیشنهاد نمی شود.
فرض کنید قصد داریم یک میلیون عدد را در عدد ۲ ضرب کنیم.
numbers = []
for i in range(1000000):
numbers.append(i * 2)این کد کاملا درست کار می کنند، اما برای حجم بالایی از داده ها چندان بهینه نیست.
استفاده از NumPy:
حالا همین عملیات را با NumPy انجام میدهیم.
import numpy as np
numbers = np.arange(1000000)
result = numbers * 2
در این روش، عملیات بسیار سریع تر اجرا می شود، زیرا بسیاری از محاسبات در سطح پایین تر و بهینه تر انجام می شوند.
بسیار از توسعه دهندگان به صورت پیش فرض از حلقه های تو در تو استفاده می کنند در حالی که بسیاری از مواقع همان عملیات را می توان با کتابخانه NumPy در چند خط ساده تر و سریع تر انجام داد!
این موضوع وقتی پروژه بزرگ باشد اهمیت بالایی دارد چون استفاده مداوم از حلقه های سنگین می تواند به مرور زمان به یک چالش اصلی عملکرد تبدیل شود.
کاهش استفاده از حلقه های سنگین و بهره گیری از پردازش های برداری یکی از موثرترین روش ها برای افزایش سرعت پروژه های پایتون می باشد.
در بسیاری از پروژه ها، تنها با جایگزین کردن حلقه های سنتی با قابلیت های NumPy می توان بدون تغییر معماری نرمافزار، عملکرد سیستم را به شکل قابل توجهی بهبود داد.
4- استفاده از Generator ها برای کاهش مصرف حافظه:
با بزرگ تر شدن پروژه ها و افزایش حجم داده ها، مدیریت حافظه به یکی از مهم ترین چالش های برنامه نویسان تبدیل می شود! بسیاری از برنامه ها به دلیل بارگذاری حجم زیادی از اطلاعات در حافظه به مرور زمان با کاهش سرعت و افت مواجه می شوند!
این یک موضوع بسیار جدی می باشد که یک توسعه دهنده باید آن را در نظر داشته باشد و برای حل این معضل قدمی بردارد!
یکی از قابلیت های کاربردی پایتون برای حل این مشکل Generator ها می باشند!
Generator ها به جای اینکه تمام داده ها را به صورت یکجا در رم ذخیره کند آن ها را در زمان نیاز و به صورت مرحله ای تولید می کند به همین دلیل مصرف حافظه RAM به شکل قابل توجهی کاهش پیدا می کند!
تفاوت List و Generator:
بسیاری از توسعه دهندگان برای پردازش داده ها به صورت پیشفرض از List استفاده می کنند.
مثال:
numbers = [i for i in range(10000000)]در این روش، تمامی دادهها همزمان در حافظه ذخیره میشوند.
اما با استفاده از Generator میتوان همین کار را به شکل بهینهتری انجام داد.
numbers = (i for i in range(10000000))در این حالت، داده ها فقط در زمان نیاز تولید می شوند و رم بسیار کمتری مصرف خواهد شد.
ساخت Generator با yield:
یکی از ساده ترین روش های ساخت Generator استفاده از کلمه کلیدی yield است.
def generate_numbers():
for i in range(5):
yield i
for number in generate_numbers():
print(number)هر بار که حلقه اجرا می شود، فقط یک مقدار تولید خواهد شد و نیازی به ذخیره تمام داده ها در حافظه نیست.
استفاده از Generator ها در شرایطی که نیاز به پردازش فایل های حجیم یا حجم زیادی از داده ها وجود دارد و پردازش لاگ های سرور نیاز به بررسی دارد بسیار کاربری هست! در شرایط وب اسکرپینگ و پردازش داده های استریم هم بسیار مناسب می باشد.
یکی از اشتباهات رایجی که در پروژه های بزرگ پیش می آید این است که ذخیره تمام داده ها در Ram اتفاق می افتد! در ابتدا این کار مشکلی ایجاد نمی کند ولی وقتی حجم داده ها بالا برود فشار مضاعفی بوجود می آید و به یکی از چالش ها و معضلات اصلی بدل می شود.
5- استفاده از Caching برای جلوگیری از محاسبات تکراری:
تقریبا همیشه استفاده از کش ها در هر سیستم و پروژه ای باعث می شود که سرعت افزایش یابد و فشار پروژه بر روی منابع سخت افزاری کاهش یابد! پایتون هم از این قاعده مستثنی نیست!
یکی از روش های بسیار موثر افزایش سرعت در پروژه های پایتونی استفاده از Cache می باشد! در بسیاری از پروژه ها برخی توابع یا عملیات ها بارها و بارها با ورودی یکسان اجرا می شوند و هر بار منابع پردازشی را درگیر می کنند!
وقتی از کش استفاده می شود این کار کمک می کند نتیجه یک عملیات پس از اولین اجرا ذخیره شود و در دفعات بعدی به جای اجرای مجدد کد همان نتیجه از حافظه بازیابی شود و این کار زمان اجرای برنامه را به شکل محسوسی کاهش می دهد!
پایتون از ابزارهای آماده برای پیاده سازی کش استفاده می کند و آن را در اختیار توسعه دهندگان قرار می دهد که مهم ترین آن functools.lru_cache و functools.cache می باشد!
استفاده از lru_cache:
یکی از رایج ترین روش ها استفاده از lru_cache می باشد که در مثال زیر تابع fibonacci بدون انجام محاسبات تکراری اجرا می شود.
پارامتر maxsize مشخص می کند که چند نتیجه در حافظه ذخیره شود!
اگر محدودیتی برای تعداد داده های ذخیره شده ندارید می توانید cache استفاده کنید.
این روش از نظر پیاده سازی ساده تر هست و تمام نتایج را هم در حافظه نگه می دارد!
زمانی که محاسبات سنگین و تکراری وجود دارد در کنار درخواست های پرتکرار API و پردازش داده ها و عملیات هایی که زمان بر است استفاده از کش بسیار کاربردی و کمک کننده هست و می تواند سرعت پروژه ها را تا حد بسیار زیادی بهبود دهد!
برخی از توسعه دهندگان تمام توابع برنامه را کش می کنند که این کار باعث افزایش مصرف حافظه می شود که این کار کاملا اشتباه می باشد! استفاده از کش فقط برای بخش هایی مناسب هست که خروجی آن ها ثابت هست یا در طی مدت زمان طولانی تغییر نمی کند و با ورودی های مشابه نتیجه یکسان تولید می کنند!
اگر از کش برای توابعی استفاده شود که پاسخ های متنوع دارد هر بار باید مجدد کد اجرا شود و استفاده از کش صرفا باعث افزایش مصرف حافظه و فشار روی منابع سرور می شود.
کش یکی از ساده ترین راهکار ها برای افزایش سرعت پایتون می باشد و در بسیاری از پروژه ها تنها با چند خط کد و استفاده از ابزار های داخلی پایتون می توان از محاسبات تکراری جلوگیری کرد!
برخی توسعهدهندگان تمام توابع برنامه را کش میکنند. این کار میتواند باعث افزایش مصرف حافظه شود.
6- استفاده از Asyncio برای بهینه سازی عملیات I/O:
یکی دیگر از دلایل رایجی که باعث کند شدن پروژه های پایتون می شود انتظار برای دریافت پاسخ از منابع خارجی است! برای مثال هنگام ارسال درخواست به API، اجرای کوئری های دیتابیس، دانلود فایل و … برنامه بخشی از زمان خود را صرف انتظار پاسخ می کند!
اگر این عملیات ها به صورت معمولی و پشت سرهم اجرا شوند زمان پاسخگویی به شدت افزایش پیدا می کند در چنین شرایط استفاده Asyncio می تواند عملکرد برنامه را به شکل قابل توجهی بهبود دهد!
Asyncio یکی از قابلیت های داخلی پایتون برای اجرای همزمان عملیات های I/O محور است این ابزار به برنامه اجازه می دهد تا در زمان انتظار برای یک عملیات کارهای دیگری را نیز انجام می دهد!
این کار کمک می کند که کل سیستم منتظر یک پاسخ نماند و به درخواست های دیگر همزمان رسیدگی کند و سیستم کند نشود! البته باید توجه داشته باشید Asyncio برای پردازش های سی پیو محور طراحی نشده است و بیشتر برای سناریو هایی کاربرد دارد که برنامه زمان زیادی را صرف انتظار پاسخ می کند!
استفاده از این قابلیت در ارتباط با API ها و اجرای Query های دیتابیس و دانلود فایل و وب اسکرپینگ بسیار کاربری هست و برای پردازش درخواست های همزمان هم عملکرد بسیار مناسبی دارد!
در مثال زیر، دو عملیات به صورت همزمان اجرا میشوند.
import asyncio
async def task(name):
print(f"شروع {name}")
await asyncio.sleep(2)
print(f"پایان {name}")
async def main():
await asyncio.gather(
task("وظیفه اول"),
task("وظیفه دوم")
)
asyncio.run(main())در این مثال، هر دو وظیفه به صورت همزمان اجرا می شوند و زمان کلی اجرای برنامه کاهش پیدا می کند.
استفاده از Asyncio مزایای زیادی دارد که مهمترین آنها عبارتاند از:
کاهش زمان پاسخگویی برنامه
مدیریت بهتر درخواست های همزمان
افزایش بهره وری در عملیات I/O
مناسب برای سرویس های پرترافیک
استفاده بهینه تر از منابع سیستم
یکی از رایج ترین اشتباهات، استفاده از Asyncio برای پردازش های سنگین محاسباتی است.
برای مثال، اگر برنامه شما شامل پردازش تصاویر، محاسبات پیچیده یا تحلیل دادههای حجیم باشد، Asyncio گزینه مناسبی نیست و بهتر است از Multiprocessing استفاده کنید.
7- دور زدن محدودیت GIL با استفاده از Multiprocessing:
یکی از مهم ترین دلایلی که باعث می شود پایتون در برخی پروژه های عملکرد ضعیف تری نسبت به زبان هایی مانند C، C++ و Go داشته باشد وجود قابلیتی به نام Global Interpreter Lock می باشد!
GIL مکانیزمی در مفسر استاندارد پایتون است که اجازه می دهد در هر لحظه فقط یک Thread کدهای پایتون را اجرا کند! این محدودیت برای مدیریت بهتر حافظه و جلوگیری از مشکلات همزمانی طراحی شده است اما می تواند روی عملکرد پروژه های سنگین اثر منفی داشته داشته باشد!
به همین دلیل برخلاف تصور بسیاری از توسعه دهندگان افزایش تعداد Thread ها همیشه باعث افزایش سرعت برنامه نمی شود! این مورد به خصوص در پردازش های CPU محور بیشتر خودش را نشان می دهد!
برای مثال فرض کنید برنامه شما باید کارهای زیر را انجام دهد:
پردازش تصاویر و ویدئوها
محاسبات پیچیده ریاضی
پردازش حجم زیادی از داده ها
شبیه سازی های علمی
الگوریتم های هوش مصنوعی
در این موارد استفاده از Thread های بالا معمولا تاثیر چشم گیری روی سرعت نخواهد شد! در این شرایط پایتون از ابزاری به نام Multiprocessing استفاده می کند و آن را در اختیار توسعه دهندگان قرار می دهد.
Multiprocessing به جای ایجاد چند thread در واقع چند process مستقل ایجاد می کند و هر پردازش برای خود حافظه اختصاصی دارد و می تواند به صورت جداگانه روی هسته های مختلف پردازنده اجرا شود!
به همین دلیل برنامه قادر خواهد بود از تمام توان پردازنده استفاده کند.
در مثال زیر، پردازش بین چند Process تقسیم می شود.
from multiprocessing import Pool
def square(number):
return number * number
with Pool() as pool:
result = pool.map(square, [1, 2, 3, 4, 5])
print(result)خروجی:
[1, 4, 9, 16, 25]در این مثال، پایتون وظایف را بین چند Process مستقل تقسیم می کند و پردازش ها به صورت موازی اجرا می شوند.
استفاده از Multiprocessing در شرایط زیر بسیار کاربردی است:
پردازش داده های حجیم
پردازش تصاویر و ویدئو ها
محاسبات پیچیده ریاضی
پروژه های هوش مصنوعی
پردازش فایل های بزرگ
انجام تسک های CPU محور
در این شرایط Multiprocessing بسیار می تواند موفق عمل کند و سرعت پروژه را افزایش دهد.
تفاوت Asyncio و Multiprocessing:
بسیاری از توسعه دهندگان این دو مفهوم را عموما با یکدیگر اشتباه می گیرند ولی با یک قانون ساده می توانید همیشه بخاطر بسپارید که اگر:
برنامه منتظر پاسخ API، دیتابیس یا دانلود فایل است، از Asyncio استفاده کنید.
برنامه درگیر محاسبات سنگین پردازنده است، از Multiprocessing استفاده کنید.
یکی از اشتباهات رایج استفاده از Thread ها برای افزایش سرعت پردازش های سنگین است! به دلیل وجود GIL این کار در بسیاری از موارد نتیجه خاصی نخواهد داشت و همچنین استفاده بی رویه از Multiprocessing هم می تواند باعث افزایش مصرف حافظه شود زیرا هر پردازش نیاز به حافظه مستقل دارد!
درک محدودیت GIL یکی از مهم ترین مباحث بهینه سازی در پایتون است.
این قانون را همیشه به خاطر داشته باشید:
عملیات I/O محور = Asyncio
عملیات CPU محور = Multiprocessing
8- بهینه سازی مصرف Ram یا Memory Optimization:
مدیریت حافظه یکی از مهم ترین بخش های بهینه سازی در پایتون می باشد بسیاری از پروژه ها ابتدا با حجم کمی از داده ها کار می کنند و خوب مشکل خاصی هم ندارند اما با بزرگ تر شدن برنامه و افزایش تعداد کاربران و پردازش داده های بیشتر مصرف حافظه به یکی از چالش های اصلی بدل می شود!
مصرف بیش از حد Ram می تواند باعث کاهش سرعت برنامه و افزایش فشار روی سرور شود و حتی می تواند باعث شود پروژه از کار بیفتد و داون تایم های طولانی ایجاد شود! باید این نکته مهم را در نظر داشته باشید اگر رم به صورت بهینه استفاده نشود کل سرور می تواند کرش کند و داون تایم های بدی را در پیک مصرف ایجاد کند و افزایش میزان Ram سرور هم فقط هزینه های سخت افزار را به پروژه تحمیل می کند!
بنابراین با توجه به موارد گفته شده بهینه سازی Ram می تواند بهترین گزینه باشد! پایتون ابزارها و تکنیک های مختلفی را برای مدیریت بهتر حافظه در اختیار توسعه دهندگان قرار داده است!
استفاده از __slots__:
به صورت پبشفرض در پایتون هر object فضای حافظه نسبتا زیادی را اشغال می کند زیرا اطلاعات مربوط به ویژگی های آن را در یک دیکشنری داخلی ذخیره می کند.
اگر تعداد زیادی object ایجاد می کنید، استفاده از __slots__ میتواند مصرف حافظه را کاهش دهد.
مثال:
class User:
__slots__ = ("name", "age")
def __init__(self, name, age):
self.name = name
self.age = ageاین روش در پروژه هایی که هزاران یا میلیون ها object ایجاد می کند بسیار کاربردی و مناسب می باشد.
استفاده از Generator و Iterator:
همان طور که در بخش های قبلی اشاره شد، بارگذاری همه داده ها در حافظه کار درستی نیست.
به جای این روش:
numbers = [i for i in range(1000000)]میتوان از Generator استفاده کرد:
numbers = (i for i in range(1000000))در این حالت، داده ها فقط در زمان نیاز تولید می شوند و حافظه کمتری مصرف خواهد شد.
حذف متغیرهای غیرضروری:
یکی از اشتباهات رایج در پروژه های بزرگ، نگهداری متغیرهایی است که دیگر مورد استفاده قرار نمی گیرند.
برای مثال:
data = get_large_data()
process(data)
del dataحذف متغیرهای غیرضروری میتواند به آزاد شدن حافظه کمک کند.
این موضوع در شرایطی که پردازش ححم زیادی از داده ها نیاز به انجام هست و پروژه هایی می باشد که ترافیک بالاست یا پروژه مربوط به هوش مصنوعی می باشد اهمیت بیشتری دارد!
خیلی از توسعه دهندگان فقط روی افزایش سرعت برنامه تمرکز می کنند و مصرف حافظه را نادیده می گیرند در حالی که در پروژه های بزرگ مصرف بیش از حد حافظه می تواند به اندازه کند بودن برنامه مشکل ساز شود!
9- بهینه سازی کوئری های دیتابیس در پروژه های Django و Flask:
در بسیاری از پروژه های پایتون خیلی از معضلات و مشکلاتی که رخ می دهد در واقع نحوه عملکرد خود برنامه نیست بلکه نحوه ارتباط با دیتابیس هست! یعنی حتی اگر کدهای سیستم شما کاملا بهینه و بدون نقص باشد! اجرای Query های غیربهینه می تواند باعث کند شدن کل سیستم شود!
این موضوع در پروژه های بزرگ Django و Flask اهمیت بیشتری پیدا می کند زیرا با افزایش تعداد کاربران، تعداد درخواست های ارسالی به دیتابیس نیز افزایش خواهد یافت.
خوشبختانه با رعایت چند تکنیک ساده میتوان فشار روی دیتابیس را کاهش داد و زمان پاسخگویی برنامه را بهبود بخشید.
استفاده از Indexing:
ایندکس کردن یکی از مهم ترین ابزارها برای افزایش سرعت جستجو در دیتابیس هست! بدون ایندکس دیتابیس برای پیدا کردن اطلاعات همیشه مجبور است تعداد زیادی از رکورد ها را بررسی کند و همین مورد باعث افت عملکرد و تاخیر در سرعت پاسخگویی می شود!
برای مثال، اگر جستجوها معمولا بر اساس ایمیل کاربران انجام می شوند، بهتر است روی این ستون ایندکس ایجاد شود.
نمونه در Django:
class User(models.Model):
email = models.EmailField(db_index=True)البته نباید روی تمام ستون ها ایندکس ایجاد کرد، زیرا این کار می تواند سرعت عملیات ثبت و بروزرسانی داده ها را کاهش دهد.
استفاده از Pagination:
یکی از اشتباهات رایج، بارگذاری تمام اطلاعات به صورت همزمان است.
برای مثال، نمایش ۱۰ هزار محصول در یک درخواست، فشار زیادی به دیتابیس وارد می کند.
روش بهتر، صفحه بندی کردن است.
نمونه در Django:
from django.core.paginator import Paginator
products = Product.objects.all()
paginator = Paginator(products, 20)
page = paginator.get_page(1)در این مثال، فقط 20 رکورد در هر صفحه نمایش داده می شود.
حذف مشکل N+1 Query:
مشکل دیگر رایج در پروژه های جنگو مشکل N+1 Query می باشد! این مشکل زمانی رخ می دهد که برنامه برای دریافت اطلاعات مرتبط تعداد زیادی query غیرضروری به دیتابیس ارسال کند!
روش غیر بهینه:
for order in orders:
print(order.user.name)در این حالت ممکن است برای هر سفارش یک کوئری جداگانه اجرا شود.
روش بهینه:
orders = Order.objects.select_related("user")
for order in orders:
print(order.user.name)استفاده از select_related باعث می شود اطلاعات مورد نیاز با یک کوئری دریافت شوند.
استفاده از Connection Pooling:
ایجاد اتصال جدید به دیتابیس برای هر درخواست می تواند باعث مشکلات زیادی به خصوص در پروژه های پرترافیک شود!
Connection Pooling با نگهداری اتصال های آماده، زمان برقراری ارتباط با دیتابیس را کاهش می دهد و عملکرد برنامه را بهبود می بخشد.
این کار شاید در ابتدای راه اندازی پروژه چندان پر اهمیت نباشد اما وقتی تعداد کاربران افزایش یافت و ترافیک ورودی بالا رفت بدون آن مصرف حافظه و درگیری های دیتابیس به شدت بالا می رود و باعث افت عملکرد فاحش پروژه می شود.
به طور کلی بهینه سازی دیتابیس یکی از مهم ترین بخش ها برای افزایش عملکرد پروژه های Django و Flask است!
استفاده از تکنیک هایی مانند Indexing، Pagination، Connection Pooling و حذف مشکل N+1 Query می تواند سرعت پاسخگویی برنامه را به شکل محسوسی افزایش دهد و فشار روی سرور را کاهش دهد.
10- استفاده از کامپایلرها و ابزار های افزایش سرعت در پایتون:
با روش های گفته شده قبلی در صورتی که به شکل اصولی و حرفه ای پیاده شود سرعت و عملکرد پروژه به شکل چشم گیری افزایش پیدا می کند اما اگر همچنان می خواهید پروژه عملکرد بهتری داشته باشد می توانید ابزارهای تخصصی پایتون در خصوص افزایش سرعت استفاده کنید!
اگرچه پایتون به دلیل سادگی و انعطاف پذیری محبوبیت زیادی دارد، اما در برخی پردازش های سنگین نمی تواند به سرعت زبان های کامپایل شده ای مانند C و C++ برسد.
با این وجود ابزار هایی وجود دارد که این محدودیت ها را تا حد زیادی برطرف می کنند و سه مورد از مهم ترین این ابزارها Cython، Numba و PyPy می باشد!
استفاده از Cython:
Cython در واقع ترکیبی از پایتون و زبان C می باشد که به شما اجازه می دهد بخش های حساس برنامه را کامپایل کنید! این ابزار های برای پروژه هایی مناسب هست که محاسبات سنگین انجام می دهند و نیاز به عملکرد بالاتری دارند!
برای مثال می توانید نوع داده ها را به صورت مشخص تعریف کنید تا سرعت اجرای کد بالاتر برود!
def multiply(int a, int b):
return a * bالبته استفاده از Cython معمولا در پروژه های پیشرفته تر و بخش های بسیار حساس از نظر عملکرد توصیه می شود و نیاز نیست برای پروزه های سبک از آن استفاده شود!
استفاده از Numba:
Numba یکی دیگر از ابزارهای ساده برای افزایش سرعت پایتون می باشد که از تکنیک JIT یا همان Jsut In Time استفاده می کند و در بسیاری از موارد سرعت اجرای برنامه را به شکل محسوسی افزایش می دهد.
مثال:
from numba import jit
@jit
def calculate():
total = 0
for i in range(1000000):
total += i
return totalNumba به خصوص در پردازش های عددی، علم داده و یادگیری ماشین بسیار محبوب است.
استفاده از PyPy:
PyPy یک مفسر جایگزین برای پایتون است که از JIT Compiler استفاده می کند و در بسیاری از پروژه ها می تواند بدون تغییر کدها، سرعت اجرای برنامه را افزایش دهد.
در برخی سناریوها، PyPy عملکرد بسیار بهتری نسبت به مفسر استاندارد پایتون CPython ارائه می دهد.
البته باید توجه داشته باشید که همه کتابخانهها به طور کامل با PyPy سازگار نیستند و بهتر است قبل از استفاده، سازگاری پروژه خود را بررسی کنید.
به طور کلی این ابزار ها در شرایط زیر عموما عملکرد بهتری از خود نشان می دهند:
پردازش های سنگین محاسباتی
پروژه های هوش مصنوعی و یادگیری ماشین
تحلیل داده های حجیم
شبیه سازی های علمی
سرویس هایی که به عملکرد بسیار بالا نیاز دارند
یکی از اشتباهاتی که زیاد دیده می شود این است که بعضی از توسعه دهندگان همان ابتدای پروژه سراغ این ابزارها می روند در حالی که این کار معمولا ضروری نیست!
همیشه ابتدا باید مشکلات برنامه بررسی و شناسایی شود و با تکنیک های ساده تر مانند Profiling و انتخاب ساختار داده مناسب و فعال کردن کش و بهینه سازی دیتابیس تا جای ممکن سرعت را افزایش داد و تنها در شرایطی که واقعا به این ابزار ها نیاز بود از آن ها استفاده کرد.
به طور کلی ابزار هایی نظیر Cython، Numba و PyPy برای افزایش سرعت مناسب هستند اما نباید به عنوان اولین قدم راهکار بهینه سازی به آن ها نگاه کرد! این ابزارها زمانی بیشترین تاثیر را دارند که سایر تکنیک های بهینه سازی گفته شده پیاده سازی شود و همچنان نیاز به عملکرد بهتر و سرعت بالاتر باشد!
11- استفاده از نسخه های جدید پایتون:
خیلی از توسعه دهندگان از زمان بارگذاری پروژه به مدت سال ها از نسخه های قدیمی پایتون استفاده می کنند این در حالی است که هر نسخه جدید علاوه بر اضافه شدن قابلیت های جدیدتر٬ بهبود های قابل توجهی هم در عملکرد دارد!

تیم توسعه پایتون در هر نسخه٬ بخش های مختلفمفسر را بهینه تر می کنند تا برنامه ها سریعتر اجرا شوند و مصرف حافظه و منابع سخت افزاری کاهش پیدا کند و طبیعتا پروژه عملکرد مطلوب تری از خود به نمایش بگذارد!
شاید بهتر است قبل از اینکه زمان و هزینه زیادی را برای بهینه سازی صرف کنید ابتدا اطمینان حاصل کنید که از یک نسخه بروز و پایدار پایتون استفاده می کنید و در بسیاری از مواقع تنها با ارتقای نسخه پایتون می توانید بدون تغییر ساختار برنامه بخشی از مشکلات کندی و مصرف های عجیب پروژه را حل کنید!
شاید در ابتدا این کار خیلی به نظر گره گشا نباشد! ولی فقط با بروزرسانی هست که خواهید دید آنقدر هم که فکر می کنید این مورد بی فایده نیست و بروزرسانی چه تاثیرات مثبتی را می تواند به همراه داشته باشد جدا از این که امکانات بیشتری هم اضافه می شود!
نسخه فعلی پایتون را بررسی کنید:
برای مشاهده نسخه نصب شده، از دستور زیر استفاده کنید:
python --versionیا:
python3 --versionاستفاده از نسخه های جدید مزایای متعددی دارد که مهم ترین آن ها عبارتند از:
بهبود سرعت اجرای برنامه ها
بهینه تر شدن مدیریت حافظه
افزایش پایداری و امنیت
رفع باگ های نسخه های قدیمی
سازگاری بهتر با کتابخانه های جدید
بنابراین نباید ارتقا پایتون را کم اهمیت تلقی کرد و در شرایط زیر حتما توصیه می شود نسخه را ارتقا دهید!
هنگام شروع یک پروژه جدید
زمانی که از نسخه های قدیمی مانند 3.7 یا 3.8 استفاده می کنید
زمانی که برخی کتابخانه ها دیگر از نسخه فعلی پشتیبانی نمی کنند
زمانی که به قابلیتهای جدید پایتون نیاز دارید!
یکی از اشتباهات رایجی که توسعه دهندگان انجام می دهند است که زمان زیادی صرف بهینه سازی می کنند در حالی که پروژه همچنان روی نسخه های قدیمی پایتون در حال اجرا می باشد!
حتما قبل از بروزرسانی سازگاری کتابخانه ها و فریم ورک های استفاده شده در پروژه را بررسی کنید تا با نسخه های جدید مطابقت داشته باشند تا بعد بروزرسانی دچار مشکل نشوید!
بک آپ گیری قبل از فرآیند ارتقا نسخه هم می تواند به شما در زمان بروز مشکل کمک زیادی کند!
12- مدیریت کتابخانه ها و حذف وابستگی های غیرضروری:
اما موردی که تقریبا در تمام بهینه سازی ها نادیده گرفته می شود و تیم های توسعه کمتر به آن توجه می کنند در صورتی که مورد مهمی می باشد مدیریت صحیح کتابخانه ها و وابستگی های پروژه می باشد!
بسیاری از توسعه دهندگان در طول زمان کتابخانه های متعددی را به پروژه اضافه می کنند و در ادامه روند توسعه شاید دیگر از آن کتابخانه ها استفاده نشود ولی همچنان در پروژه باقی می مانند!
هر کتابخانه ای که به پروژه اضافه می شود هزینه های مربوط به خود را دارد و استفاده بیش از حد از پکیج های غیرضروری می تواند باعث افزایش مصرف حافظه و افزایش زمان راه اندازی برنامه شود و حتی امکان ایجاد مشکلات امنیتی در این پروژه ها بیشتر هم می شود!
این دقیقا همان دلایلی هست که بهتر است به صورت دوره ای وابستگی پروژه مورد بررسی قرار بگیرد و موارد غیرضروری حذف شود!
گاهی اوقات برای انجام یک کار ساده کتابخانه های سنگین به پروژه اضافه می شود در حالی که همان قابیلت با امکانات داخلی پایتون هم قابل پیاده سازی هست!
بنابراین قبل از اضافه کردن هر پکیج ابتدا از خود بپرسید آیا واقعا به این کتابخانه نیاز دارم؟
هرچه تعداد وابستگی های پروژه کمتر باشد، نگهداری آن نیز ساده تر خواهد بود.
وابستگی های بدون استفاده را حذف کنید:
در بسیاری از پروژه ها کتابخانه هایی وجود دارند که شاید در گذشته استفاده می شدند اما الان دیگر کاربردی ندارند و حذف این کتابخانه ها باعث می شود پروژه سبک تر شود و مدیریت آن هم ساده تر شود!
برای مشاهده کتابخانههای نصب شده میتوانید از دستور زیر استفاده کنید:
pip listهمچنین برای حذف یک کتابخانه از دستور زیر استفاده میشود:
pip uninstall package_name
بهتر است نسخه کتابخانه های پروژه را مشخص و کنترل کنید تا در آینده با مشکلات ناسازگاری مواجه نشوید.
استفاده از فایل requirements.txt یکی از روش های رایج برای مدیریت وابستگی ها است.
برای ذخیره وابستگی های فعلی می توانید از دستور زیر استفاده کنید:
pip freeze > requirements.txt
یکی دیگر از اشتباهات رایج، نصب چندین کتابخانه با وظایف تقریبا یکسان است و این کار هم باعث افزایش حجم پروژه و مدیریت و بروزرسانی را دشوارتر می کند!
تا حد امکان سعی کنید از ابزارهای استاندارد و کتابخانه های شناخته شده استفاده کنید.
مدیریت وابستگیها شاید در نگاه اول اهمیت زیادی نداشته باشد، اما در پروژه های بزرگ میتواند تاثیر مستقیمی بر عملکرد، امنیت و نگهداری نرم افزار داشته باشد. هرچه پروژه سبک تر باشد عملکرد بهتری را از خود به نمایش خواهد گذاشت!
تاثیر هاست مناسب در عملکرد بهینه پروژه های پایتونی:
در کنار تمام مواردی که برای افزایش سرعت و بهینه سازی پروژه های پایتونی ذکر کردیم نباید از تاثیر یک هاست و سرور مناسب برای اجرای پروژه های پایتونی چشم پوشی کرد!
حتی اگر پروژه پایتونی از نظر ساختار کد٬ کوئری های دیتابیس، مدیریت حافظه و پردازش درخواست ها کاملا بهینه شده باشد، استفاده از یک هاست نامناسب می تواند نتیجه تمام این بهینه سازی ها را تحت تاثیر قرار دهد.
میزان منابع پردازنده و حافظه، سرعت فضای ذخیره سازی، نوع وب سرور، کیفیت شبکه، تعداد درخواست های هم زمان قابل پردازش و محدودیت های اعمال شده روی سرویس، همگی می توانند روی سرعت پاسخگویی پروژه تاثیر داشته باشند.
برای مثال، کمبود حافظه ممکن است باعث بسته شدن پردازش های پایتون شود و محدود بودن CPU نیز می تواند زمان اجرای عملیات های سنگین یا پاسخگویی به درخواست های هم زمان را افزایش دهد.
انتخاب نسخه مناسب پایتون نیز فقط به کدهای پروژه وابسته نیست و محیط میزبانی باید امکان استفاده از نسخه های جدید و سازگار با کتابخانه ها و فریم ورک های پروژه را فراهم کند. علاوه بر این، دسترسی به ابزارهایی مانند pip، SSH و Git و امکان استفاده از دیتابیس هایی مانند MySQL، PostgreSQL، Redis و MongoDB می تواند فرآیند توسعه، استقرار و مدیریت پروژه را ساده تر کند.
در پروژه هایی که با Django، Flask، FastAPI یا سایر فریم ورک های پایتون توسعه داده شده اند، هماهنگی محیط میزبانی با ساختار پروژه اهمیت بیشتری پیدا می کند. استفاده از یک هاست پایتون که از اجرای مستقیم پروژه های پایتونی، نسخه های مختلف این زبان و ابزارهای مورد نیاز توسعه دهنده پشتیبانی کند، می تواند بسیاری از پیچیدگی های مربوط به راه اندازی و نگهداری سرور را کاهش دهد.
البته افزایش منابع هاست نباید جایگزین بهینه سازی نرم افزار شود! اگر برنامه با مشکلاتی مانند کوئری های سنگین، مصرف بی رویه حافظه، حلقه های غیربهینه یا پردازش های تکراری مواجه باشد، انتقال آن به یک سرویس قوی تر تنها برای مدتی مشکل را پنهان خواهد کرد.
بهترین نتیجه زمانی به دست می آید که کد بهینه در کنار زیرساخت مناسب قرار بگیرد. توسعه دهنده باید ابتدا نیاز واقعی پروژه را بررسی کند و سپس براساس تعداد کاربران، میزان مصرف منابع، نوع دیتابیس، حجم پردازش ها و پیش بینی رشد آینده، سرویس میزبانی مناسبی را انتخاب کند.
نتیجه گیری:
همیشه این مورد را بخاطر بسپارید که بهینه سازی در پایتون صرفا به معنای افزایش سرعت اجرای چند خط کد نیست! بلکه نوعی طرز فکر در طراحی و توسعه نرم افزار می باشد!
بسیاری از توسعه دهندگان در مراحل ابتدایی فکر می کنند می توانند به هر شکلی کد های خود را بنویسند و در مراحل پایانی در صورتی که دچار مشکل شدند شروع به بهینه سازی کنند! این طرز فکر به طور کامل اشتباه هست چون بعد از انتشار پروژه با رشد و بزرگ تر شدن آن و ورود کاربران بیشتر به پروژه امکان هر تصمیمی سخت تر می شود و امکان بروز مشکلات زیادی وجود دارد.
انتخاب یک ساختار داده نامناسب، طراحی غیر اصولی ارتباط با دیتابیس یا استفاده نادرست از منابع سیستم، شاید در مراحل ابتدایی توسعه چندان محسوس نباشد، اما در مقیاس بزرگ به سرعت خود را نشان می دهد.
نکته مهم این است که بهینه سازی همیشه به معنای پیچیده تر کردن نرم افزار نیست. در بسیاری از مواقع، ساده تر کردن کدها، حذف وابستگی های غیرضروری، انتخاب ابزار مناسب و استفاده صحیح از قابلیت های داخلی پایتون میتواند تاثیر بیشتری نسبت به راهکار های پیچیده داشته باشد.
این مورد را هم بخاطر بسپارید که هیچ راهکاری واحدی وجود ندارد که برای همه پروژه ها پاسخگو باشد! یک برنامه مبتنی بر هوش مصنوعی به طور کامل نسبت به یک فروشگاه اینترنتی متفاوت هست و طبیعتا هر کدام چالش های خاص خود را دارند و با توجه به پروژه باید استراتژی مناسب بهینه سازی را پیدا و پیاده سازی کرد!
پایتون به لطف اکوسیستم گسترده، کتابخانه های قدرتمند و ابزارهای متنوع، امکانات بسیار زیادی برای ساخت نرم افزار های سریع، مقیاس پذیر و پایدار در اختیار توسعه دهندگان قرار داده است. با این حال، بهره برداری صحیح از این امکانات نیازمند درک درست از نحوه عملکرد زبان، مدیریت منابع و انتخاب راهکار مناسب در زمان مناسب است.
در نهایت به این نکته توجه داشته باشید که هدف اصلی بهینه سازی ساخت سریع ترین نرم افزار ممکن نیست بلکه ساخت پروژه ای می باشد که بتواند در طول زمان و با افزایش حجم داده و رشد تعداد کاربران همچنان پایدار و قابل اعتماد باقی ماند و تیم توسعه را با چالش های متعدد رو به رو نکند و از نظر مصرف منابع نیاز به ارتقا های عجیب و غریب سخت افزار نداشته باشد!
بهینه سازی موفق زمانی اتفاق می افتد که میان سرعت، مصرف منابع، خوانایی کد و سادگی نگهداری پروژه تعادل برقرار شود. توسعه دهندگانی که این تعادل را در پروژه های خود ایجاد می کنند، در واقع زیرساختی می سازند که در آینده نیز پاسخگوی نیازهای کسب و کار و کاربران خواهد بود.
مقالات مرتبط:
چرا یادگیری هوش مصنوعی با پایتون یک ضرورت هست!
بررسی کامل امنیت در پایتون؛ تهدیدها و راهکار مقابله












