از این تکنیک ها برای اجرای همزمان کد استفاده کنید و تجربه کاربری روان تری را ارائه دهید.
نکات کلیدی
- همزمانی و موازی بودن اصول اساسی اجرای کار در محاسبات هستند که هر کدام دارای ویژگی های متمایز خود هستند.
- همزمانی امکان استفاده کارآمد از منابع و بهبود پاسخگویی برنامه ها را فراهم می کند، در حالی که موازی سازی برای عملکرد بهینه و مقیاس پذیری بسیار مهم است.
- پایتون گزینه هایی را برای مدیریت همزمانی، مانند threading و برنامه نویسی ناهمزمان با asyncio و همچنین موازی سازی با استفاده از ماژول چند پردازشی ارائه می دهد.
همزمانی و موازی دو تکنیکی هستند که به شما امکان می دهند چندین برنامه را به طور همزمان اجرا کنید. پایتون چندین گزینه برای انجام وظایف به صورت همزمان و موازی دارد که ممکن است گیج کننده باشد.
ابزارها و کتابخانه های موجود برای اجرای درست همزمانی و موازی سازی در پایتون و تفاوت آنها را بررسی کنید.
درک همزمانی و موازی سازی
همزمانی و موازی بودن به دو اصل اساسی اجرای کار در محاسبات اشاره دارد. هر کدام ویژگی های متمایز خود را دارند.
- همزمانی توانایی یک برنامه برای مدیریت چندین کار به طور همزمان است بدون اینکه لزوماً آنها را دقیقاً همزمان اجرا کند. حول محور ایده درهم تنیدگی وظایف، جابهجایی بین آنها به شیوهای که همزمان به نظر میرسد، میچرخد.
- از سوی دیگر، موازی گرایی شامل اجرای چند کار به طور واقعی به صورت موازی است. معمولاً از چندین هسته یا پردازنده CPU بهره می برد. Parallelism به اجرای همزمان واقعی دست می یابد، به شما امکان می دهد وظایف را سریعتر انجام دهید، و برای عملیات محاسباتی فشرده مناسب است.
اهمیت همزمانی و موازی سازی
نیاز به همزمانی و موازی بودن در محاسبات را نمی توان اغراق کرد. در اینجا دلیل اهمیت این تکنیک ها آمده است:
- استفاده از منابع: همزمانی امکان استفاده کارآمد از منابع سیستم را فراهم میکند و تضمین میکند که وظایف بهجای انتظار بیهوده برای منابع خارجی، فعالانه پیشرفت میکنند.
- پاسخگویی: همزمانی می تواند پاسخگویی برنامه ها را بهبود بخشد، به خصوص در سناریوهایی که شامل رابط های کاربر یا سرورهای وب است.
- عملکرد: موازی سازی برای دستیابی به عملکرد بهینه بسیار مهم است، به ویژه در کارهای محدود به CPU مانند محاسبات پیچیده، پردازش داده ها و شبیه سازی.
- مقیاس پذیری: هم همزمانی و هم موازی بودن برای ساختن سیستم های مقیاس پذیر ضروری هستند.
- اثبات آینده: از آنجایی که روندهای سخت افزاری به نفع پردازنده های چند هسته ای ادامه می دهند، توانایی مهار موازی سازی به طور فزاینده ای ضروری می شود.
همزمانی در پایتون
شما می توانید در پایتون با استفاده از threading و برنامه نویسی ناهمزمان با کتابخانه asyncio به همزمانی دست پیدا کنید.
Threading در پایتون
Threading یک مکانیسم همزمانی پایتون است که به شما امکان می دهد وظایف را در یک فرآیند واحد ایجاد و مدیریت کنید. Thread ها برای انواع خاصی از کارها مناسب هستند، به ویژه آنهایی که I/O-Bound هستند و می توانند از اجرای همزمان بهره ببرند.
ماژول threading پایتون یک رابط سطح بالا برای ایجاد و مدیریت رشته ها فراهم می کند. در حالی که GIL (قفل مترجم جهانی) رشتهها را از نظر موازیسازی واقعی محدود میکند، آنها همچنان میتوانند با در همپیچیدن کارها به طور کارآمد به همزمانی دست یابند.
کد زیر نمونه ای از اجرای همزمان با استفاده از نخ ها را نشان می دهد. از کتابخانه درخواست پایتون برای ارسال یک درخواست HTTP استفاده میکند که یک کار مسدودکننده ورودی/خروجی رایج است. همچنین از ماژول زمان برای محاسبه زمان اجرا استفاده می کند.
import requests
import time
import threading
urls = [
'https://www.google.com',
'https://www.wikipedia.org',
'https://www.makeuseof.com',
]
# function to request a URL
def download_url(url):
response = requests.get(url)
print(f"Downloaded {url} - Status Code: {response.status_code}")
# Execute without threads and measure execution time
start_time = time.time()
for url in urls:
download_url(url)
end_time = time.time()
print(f"Sequential download took {end_time - start_time:.2f} seconds\n")
# Execute with threads, resetting the time to measure new execution time
start_time = time.time()
threads = []
for url in urls:
thread = threading.Thread(target=download_url, args=(url,))
thread.start()
threads.append(thread)
# Wait for all threads to complete
for thread in threads:
thread.join()
end_time = time.time()
print(f"Threaded download took {end_time - start_time:.2f} seconds")
با اجرای این برنامه باید ببینید سرعت درخواست های رشته ای چقدر بیشتر از درخواست های متوالی است. اگرچه این تفاوت فقط کسری از ثانیه است، اما هنگام استفاده از رشتهها برای وظایف I/O-bound، درک واضحی از بهبود عملکرد دریافت میکنید.
برنامه نویسی ناهمزمان با Asyncio
asyncio یک حلقه رویداد فراهم می کند که وظایف ناهمزمان به نام coroutines را مدیریت می کند. کوروتین ها توابعی هستند که می توانید آنها را متوقف کرده و از سر بگیرید و برای کارهای I/O-bound ایده آل هستند. این کتابخانه به ویژه برای سناریوهایی مفید است که وظایف شامل انتظار برای منابع خارجی مانند درخواست های شبکه است.
می توانید مثال ارسال درخواست قبلی را برای کار با asyncio تغییر دهید:
import asyncio
import aiohttp
import time
urls = [
'https://www.google.com',
'https://www.wikipedia.org',
'https://www.makeuseof.com',
]
# asynchronous function to request URL
async def download_url(url):
async with aiohttp.ClientSession() as session:
async with session.get(url) as response:
content = await response.text()
print(f"Downloaded {url} - Status Code: {response.status}")
# Main asynchronous function
async def main():
# Create a list of tasks to download each URL concurrently
tasks = [download_url(url) for url in urls]
# Gather and execute the tasks concurrently
await asyncio.gather(*tasks)
start_time = time.time()
# Run the main asynchronous function
asyncio.run(main())
end_time = time.time()
print(f"Asyncio download took {end_time - start_time:.2f} seconds")
با استفاده از کد، می توانید صفحات وب را به طور همزمان با استفاده از asyncio دانلود کنید و از عملیات ورودی/خروجی ناهمزمان بهره ببرید. این می تواند کارآمدتر از threading برای کارهای I/O-bound باشد.
موازی سازی در پایتون
شما می توانید موازی سازی را با استفاده از ماژول چند پردازشی پایتون پیاده سازی کنید، که به شما امکان می دهد تا از مزایای کامل پردازنده های چند هسته ای استفاده کنید.
چند پردازش در پایتون
ماژول چند پردازشی پایتون راهی برای دستیابی به موازی سازی با ایجاد فرآیندهای مجزا که هرکدام دارای مفسر پایتون و فضای حافظه خاص خود هستند، فراهم می کند. این به طور موثری از قفل مترجم جهانی (GIL) عبور میکند و آن را برای کارهای محدود به CPU مناسب میکند.
import requests
import multiprocessing
import time
urls = [
'https://www.google.com',
'https://www.wikipedia.org',
'https://www.makeuseof.com',
]
# function to request a URL
def download_url(url):
response = requests.get(url)
print(f"Downloaded {url} - Status Code: {response.status_code}")
def main():
# Create a multiprocessing pool with a specified number of processes
num_processes = len(urls)
pool = multiprocessing.Pool(processes=num_processes)
start_time = time.time()
pool.map(download_url, urls)
end_time = time.time()
# Close the pool and wait for all processes to finish
pool.close()
pool.join()
print(f"Multiprocessing download took {end_time-start_time:.2f} seconds")
main()
در این مثال، multiprocessing چندین فرآیند ایجاد میکند و به تابع download_url اجازه میدهد به صورت موازی اجرا شود.
زمان استفاده از همزمانی یا موازی
انتخاب بین همزمانی و موازی به ماهیت وظایف شما و منابع سخت افزاری موجود بستگی دارد.
میتوانید هنگام انجام کارهای مرتبط با ورودی/خروجی، مانند خواندن و نوشتن فایلها یا درخواستهای شبکه، و زمانی که محدودیتهای حافظه نگرانکننده هستند، از همزمانی استفاده کنید.
هنگامی که وظایف محدود به CPU دارید که میتوانند از موازیسازی واقعی بهره ببرند و زمانی که جداسازی قوی بین کارها دارید، از چند پردازش استفاده کنید، جایی که شکست یک کار نباید بر دیگران تأثیر بگذارد.
از همزمانی و موازی سازی استفاده کنید
موازی سازی و همزمانی راه های موثری برای بهبود پاسخگویی و عملکرد کد پایتون شما هستند. درک تفاوت بین این مفاهیم و انتخاب موثرترین استراتژی بسیار مهم است.
پایتون ابزارها و ماژولهایی را ارائه میکند که برای موثرتر کردن کدتان از طریق همزمانی یا موازیسازی، صرف نظر از اینکه با فرآیندهای CPU-bound یا I/O-bound کار میکنید، نیاز دارید.