Threading زمان اجرای یک برنامه را به میزان قابل توجهی کاهش می دهد. آموزش پیاده سازی Threading در پایتون.
زمان اجرا یکی از معیارهای رایج کارایی یک برنامه است. هر چه زمان اجرا سریعتر باشد برنامه بهتر است. Threading تکنیکی است که به یک برنامه اجازه می دهد تا چندین کار یا فرآیند را به طور همزمان انجام دهد.
شما یاد خواهید گرفت که چگونه از ماژول threading داخلی پایتون و ماژول concurrent.features استفاده کنید. هر دوی این ماژول ها راه های ساده ای برای ایجاد و مدیریت رشته ها ارائه می دهند
اهمیت Threading
Threading مدت زمانی که یک برنامه برای تکمیل یک کار صرف می کند را کاهش می دهد. اگر کار شامل چندین کار مستقل باشد، میتوانید از Threading برای اجرای همزمان کارها استفاده کنید و زمان انتظار برنامه را برای اتمام یک کار قبل از رفتن به کار بعدی کاهش دهید.
به عنوان مثال، برنامه ای که چندین فایل تصویری را از اینترنت دانلود می کند. این برنامه می تواند از Threading برای دانلود فایل ها به صورت موازی و نه یک بار در یک زمان استفاده کند. این زمان برنامه را حذف می کند که باید منتظر بماند تا فرآیند دانلود یک فایل قبل از رفتن به فایل بعدی کامل شود.
برنامه اولیه قبل از نخ زنی
تابع در برنامه زیر یک وظیفه را نشان می دهد. وظیفه این است که اجرای برنامه را برای یک ثانیه متوقف کنید. برنامه دو بار تابع را فراخوانی می کند و از این رو دو وظیفه ایجاد می کند. سپس زمان اجرای کل برنامه را محاسبه می کند و سپس آن را روی صفحه نمایش می دهد.
import time
start_time = time.perf_counter()
def pause():
print('Sleeping 1 second...')
time.sleep(1)
print('Done Sleeping...')
pause()
pause()
finish_time = time.perf_counter()
print(f'Finished in {round(finish_time - start_time, 2)} second(s)')
خروجی نشان می دهد که اجرای برنامه 2.01 ثانیه طول کشیده است. اجرای هر کار یک ثانیه و بقیه کد 0.01 ثانیه طول می کشد.
می توانید از threading برای اجرای همزمان هر دو کار استفاده کنید. اجرای هر دو کار یک ثانیه طول می کشد.
پیاده سازی Threading با استفاده از ماژول threading
برای تغییر کد اولیه برای پیاده سازی threading، ماژول threading را وارد کنید. با استفاده از کلاس Thread دو رشته thread_1 و thread_2 ایجاد کنید. برای شروع اجرای هر رشته، متد start را فراخوانی کنید. متد join را در هر رشته فراخوانی کنید تا قبل از اجرای بقیه برنامه منتظر بمانید تا اجرای آنها کامل شود.
import time
import threading
start_time = time.perf_counter()
def pause():
print('Sleeping 1 second...')
time.sleep(1)
print('Done Sleeping...')
thread_1 = threading.Thread(target=pause)
thread_2 = threading.Thread(target=pause)
thread_1.start()
thread_2.start()
thread_1.join()
thread_2.join()
finish_time = time.perf_counter()
print(f'Finished in {round(finish_time - start_time, 2)} second(s)')
این برنامه هر دو رشته را به طور همزمان اجرا می کند. این باعث می شود مدت زمان لازم برای انجام هر دو کار کاهش یابد.
خروجی نشان می دهد که زمان صرف شده برای اجرای همان وظایف حدود یک ثانیه است. این نیمی از زمانی است که برنامه اولیه طول کشید.
پیاده سازی Threading با استفاده از ماژول concurrent.futures
پایتون 3.2 ماژول concurrent.futures را معرفی کرد. این ماژول یک رابط سطح بالا برای اجرای وظایف ناهمزمان با استفاده از رشته ها فراهم می کند. این روش ساده تری برای اجرای موازی وظایف ارائه می دهد.
برای تغییر برنامه اولیه برای استفاده از threading، ماژول concurrent.features را وارد کنید. از کلاس ThreadPoolExecutor از ماژول concurrent.futures برای ایجاد مجموعه ای از رشته ها استفاده کنید. تابع مکث را دو بار به استخر ارسال کنید. متد submit یک شی آینده را برمی گرداند که نتیجه فراخوانی تابع را نشان می دهد.
روی معاملات آتی تکرار کنید و نتایج آنها را با استفاده از روش نتیجه چاپ کنید.
import time
import concurrent.futures
start_time = time.perf_counter()
def pause():
print('Sleeping 1 second...')
time.sleep(1)
return 'Done Sleeping...'
with concurrent.futures.ThreadPoolExecutor() as executor:
results = [executor.submit(pause) for _ in range(2)]
for f in concurrent.futures.as_completed(results):
print(f.result())
finish_time = time.perf_counter()
print(f'Finished in {round(finish_time - start_time, 2)} second(s)')
ماژول concurrent.features از شروع و پیوستن موضوعات برای شما مراقبت می کند. این باعث می شود کد شما تمیزتر شود.
خروجی با خروجی ماژول threading یکسان است. ماژول threading برای موارد ساده ای که باید چند رشته را به صورت موازی اجرا کنید مفید است. از سوی دیگر، ماژول concurrent.futures برای موارد پیچیده تری که نیاز به اجرای همزمان بسیاری از وظایف دارید، مفید است.
استفاده از Threading در یک سناریوی واقعی
استفاده از Thread برای اجرای برنامه فوق زمان را یک ثانیه کاهش داد. در دنیای واقعی، نخ ها در زمان بیشتری صرفه جویی می کنند. برنامه ای بسازید که تصاویر را از اینترنت دانلود کند. با ایجاد یک محیط مجازی جدید شروع کنید. برای نصب کتابخانه درخواست ها دستور زیر را در ترمینال اجرا کنید:
pip install requests
کتابخانه درخواست ها به شما امکان ارسال درخواست های HTTP را می دهد. کتابخانه درخواست ها و کتابخانه زمان را وارد کنید.
import requests
import time
فهرستی از URL های تصاویری که می خواهید دانلود کنید ایجاد کنید. بگذارید حداقل ده عدد باشند تا هنگام اجرای threading متوجه تفاوت قابل توجهی شوید.
img_urls = [
'https://images.unsplash.com/photo-1524429656589-6633a470097c',
'https://images.unsplash.com/photo-1530224264768-7ff8c1789d79',
'https://images.unsplash.com/photo-1564135624576-c5c88640f235',
'https://images.unsplash.com/photo-1541698444083-023c97d3f4b6',
'https://images.unsplash.com/photo-1522364723953-452d3431c267',
'https://images.unsplash.com/photo-1513938709626-033611b8cc03',
'https://images.unsplash.com/photo-1507143550189-fed454f93097',
'https://images.unsplash.com/photo-1493976040374-85c8e12f0c0e',
'https://images.unsplash.com/photo-1504198453319-5ce911bafcde',
'https://images.unsplash.com/photo-1530122037265-a5f1f91d3b99',
'https://images.unsplash.com/photo-1516972810927-80185027ca84',
'https://images.unsplash.com/photo-1550439062-609e1531270e',
]
فهرست نشانیهای اینترنتی را که هر تصویر را دانلود میکنند در همان پوشهای که پروژه شما در آن قرار دارد، بچرخانید. نمایش زمان صرف شده برای دانلود تصاویر با کم کردن زمان پایان از زمان شروع.
start_time = time.perf_counter()
for img_url in img_urls:
img_bytes = requests.get(img_url).content
img_name = img_url.split('/')[3]
img_name = f'{img_name}.jpg'
with open(img_name, 'wb') as img_file:
img_file.write(img_bytes)
print(f'{img_name} was downloaded...')
finish_time = time.perf_counter()
print(f'Finished in {finish_time - start_time} seconds')
دانلود این 12 تصویر حدود 22 ثانیه طول می کشد. ممکن است برای شما متفاوت باشد زیرا زمان دانلود تصاویر نیز به سرعت اینترنت شما بستگی دارد.
برنامه را تغییر دهید تا از threading با استفاده از ماژول concurrent.features استفاده کند. به جای حلقه، از یک تابع استفاده کنید. این تابعی است که شما به نمونه اجرا کننده ارسال خواهید کرد.
import requests
import time
import concurrent.futures
img_urls = [
'https://images.unsplash.com/photo-1524429656589-6633a470097c',
'https://images.unsplash.com/photo-1530224264768-7ff8c1789d79',
'https://images.unsplash.com/photo-1564135624576-c5c88640f235',
'https://images.unsplash.com/photo-1541698444083-023c97d3f4b6',
'https://images.unsplash.com/photo-1522364723953-452d3431c267',
'https://images.unsplash.com/photo-1513938709626-033611b8cc03',
'https://images.unsplash.com/photo-1507143550189-fed454f93097',
'https://images.unsplash.com/photo-1493976040374-85c8e12f0c0e',
'https://images.unsplash.com/photo-1504198453319-5ce911bafcde',
'https://images.unsplash.com/photo-1530122037265-a5f1f91d3b99',
'https://images.unsplash.com/photo-1516972810927-80185027ca84',
'https://images.unsplash.com/photo-1550439062-609e1531270e',
]
start_time = time.perf_counter()
def download_image(img_url):
img_bytes = requests.get(img_url).content
img_name = img_url.split('/')[3]
img_name = f'{img_name}.jpg'
with open(img_name, 'wb') as img_file:
img_file.write(img_bytes)
print(f'{img_name} was downloaded...')
with concurrent.futures.ThreadPoolExecutor() as executor:
executor.map(download_image, img_urls)
finish_time = time.perf_counter()
print(f'Finished in {finish_time-start_time} seconds')
پس از معرفی نخ . زمان به طور قابل توجهی کاهش می یابد. اجرای برنامه تنها 4 ثانیه طول کشید.
سناریوهای مناسب برای Threading
برخی از سناریوهای مناسب برای threading عبارتند از:
- وظایف محدود شده ورودی/خروجی: اگر برنامه بیشتر زمان را صرف انتظار برای تکمیل عملیات ورودی یا خروجی کند. Threading می تواند عملکرد را با اجازه دادن به سایر وظایف برای اجرا در حالی که منتظر تکمیل عملیات I/O هستند، بهبود بخشد.
- خراش دادن وب: خراش دادن وب شامل ایجاد درخواست های HTTP و تجزیه پاسخ های HTML است. Threading با اجازه دادن به شما برای ایجاد چندین درخواست به طور همزمان به سرعت بخشیدن به فرآیند کمک می کند.
- وظایف محدود به CPU: Threading می تواند با اجازه دادن به چندین کار برای اجرای موازی به بهبود عملکرد کمک کند.
با Threading به زبان های دیگر آشنا شوید
پایتون تنها زبانی نیست که از Threading پشتیبانی می کند. اکثر زبان های برنامه نویسی از نوعی threading پشتیبانی می کنند. مهم است که با اجرای موضوعات در زبان های دیگر آشنا شوید. این شما را با مهارت های لازم برای مقابله با سناریوهای مختلف که ممکن است در آن نخ استفاده شود، مجهز می کند.