השחלה מקצרת משמעותית את זמן הביצוע של תוכנית. למד כיצד ליישם שרשור ב-Python.

זמן ביצוע הוא אחד המדדים הנפוצים ליעילות של תוכנית. ככל שזמן הביצוע מהיר יותר כך התוכנית טובה יותר. השחלה היא טכניקה המאפשרת לתוכנית לבצע מספר משימות או תהליכים בו זמנית.

תלמד כיצד להשתמש בפייתון המובנה הַשׁחָלָה מודול ואת concurrent.features מודול. שני המודולים הללו מציעים דרכים פשוטות ליצור ולנהל שרשורים

חשיבות השרשור

השרשור מפחית את משך הזמן שלוקח לתוכנית להשלים עבודה. אם העבודה מכילה משימות עצמאיות מרובות, אתה יכול להשתמש בשרשור כדי להפעיל את המשימות במקביל, ולצמצם את זמן ההמתנה של התוכנית עד שמשימה אחת תסתיים לפני שתמשיך לאחרת.

לדוגמה, תוכנית שמורידה מספר קובצי תמונה מהאינטרנט. תוכנית זו יכולה לנצל שרשור כדי להוריד את הקבצים במקביל ולא אחד בכל פעם. זה מבטל את הזמן שהתוכנית תצטרך לחכות עד שתהליך ההורדה של קובץ אחד יסתיים לפני שתעבור לקובץ הבא.

תוכנית ראשונית לפני השרשור

הפונקציה בתוכנית הבאה מייצגת משימה. המשימה היא להשהות את ביצוע התוכנית לשנייה אחת. התוכנית קוראת לפונקציה פעמיים ומכאן יוצרת שתי משימות. לאחר מכן הוא מחשב את הזמן שלקח לתוכנית כולה לפעול ולאחר מכן מציג אותו על המסך.

instagram viewer
יְבוּא זְמַן

start_time = time.perf_counter()

defהַפסָקָה():
הדפס('ישן שנייה אחת...')
זמן שינה(1)
הדפס("סיימתי לישון...")

הַפסָקָה()
הַפסָקָה()
finish_time = time.perf_counter()
הדפס(f'סיים ב {סיבוב (זמן_סיום - שעת_התחלה, 2)} שניות)')

הפלט מראה שהתוכנית לקחה 2.01 שניות לביצוע. כל משימה ארכה שנייה אחת ושאר הקוד לקח 0.01 שניות לביצוע.

אתה יכול להשתמש בשרשור כדי לבצע את שתי המשימות במקביל. זה ייקח לשתי המשימות שנייה אחת לביצוע.

יישום השחלה באמצעות מודול השחלה

כדי לשנות את הקוד הראשוני כדי ליישם שרשור, ייבא את ה הַשׁחָלָה מודול. צור שני שרשורים, thread_1 ו thread_2 משתמש ב פְּתִיל מעמד. תתקשר ל הַתחָלָה שיטה בכל שרשור כדי להתחיל את הביצוע שלו. תתקשר ל לְהִצְטַרֵף שיטה בכל שרשור להמתין להשלמה של ביצועם לפני ששאר התוכנית תתבצע.

יְבוּא זְמַן
יְבוּא הַשׁחָלָה
start_time = time.perf_counter()

defהַפסָקָה():
הדפס('ישן שנייה אחת...')
זמן שינה(1)
הדפס("סיימתי לישון...")

thread_1 = שרשור. שרשור (יעד=השהיה)
thread_2 = שרשור. שרשור (יעד=השהיה)

thread_1.start()
thread_2.start()

thread_1.join()
thread_2.join()

finish_time = time.perf_counter()
הדפס(f'סיים ב {סיבוב (זמן_סיום - שעת_התחלה, 2)} שניות)')

התוכנית תפעיל את שני האשכולות במקביל. זה יקטין את משך הזמן שלוקח לביצוע שתי המשימות.

הפלט מראה שהזמן שלוקח להפעלת אותן משימות הוא בסביבות שנייה. זה מחצית מהזמן שלקחה התוכנית הראשונית.

יישום שרשור באמצעות מודול concurrent.futures

Python 3.2 ראה את הצגת ה- concurrent.futures מודול. מודול זה מספק ממשק ברמה גבוהה לביצוע משימות אסינכרוניות באמצעות שרשורים. הוא מספק דרך פשוטה יותר לביצוע משימות במקביל.

כדי לשנות את התוכנית הראשונית לשימוש בהשרשור, ייבא את המודול concurrent.features. להשתמש ב ThreadPoolExecutor class מהמודול concurrent.futures ליצירת מאגר של שרשורים. שלח את הַפסָקָה לתפקד לבריכה פעמיים. ה שלח שיטה מחזירה א עתיד אובייקט המייצג את התוצאה של קריאת הפונקציה.

חזרו על ה עתידיים ולהדפיס את התוצאות שלהם באמצעות תוֹצָאָה שיטה.

יְבוּא זְמַן
יְבוּא concurrent.futures

start_time = time.perf_counter()

defהַפסָקָה():
הדפס('ישן שנייה אחת...')
זמן שינה(1)
לַחֲזוֹר"סיימתי לישון..."

עם concurrent.futures. ThreadPoolExecutor() כפי ש מוציא להורג:
תוצאות = [executor.submit (השהיה) ל _ ב טווח(2)]
ל ו ב concurrent.futures.as_completed (תוצאות):
print (f.result())

finish_time = time.perf_counter()

הדפס(f'סיים ב {סיבוב (זמן_סיום - שעת_התחלה, 2)} שניות)')

מודול concurrent.features דואג להתחיל ולהצטרף לשרשורים עבורך. זה עושה את הקוד שלך נקי יותר.

הפלט זהה לזו של מודול ההברגה. מודול השרשור שימושי למקרים פשוטים שבהם אתה צריך להריץ כמה שרשורים במקביל. מצד שני, מודול concurrent.futures שימושי למקרים מורכבים יותר שבהם אתה צריך להריץ משימות רבות במקביל.

שימוש בהברגה בתרחיש של עולם אמיתי

שימוש בשרשורים כדי להפעיל את התוכנית לעיל הקצר את הזמן בשנייה אחת. בעולם האמיתי, שרשורים חוסכים יותר זמן. צור תוכנה שמורידה תמונות מהאינטרנט. התחל ב יצירת סביבה וירטואלית חדשה. הפעל את הפקודה הבאה בטרמינל כדי להתקין את בקשות סִפְרִיָה:

בקשות להתקנת pip

ספריית הבקשות תאפשר לך לשלוח בקשות HTTP. ייבא את ספריית הבקשות ואת ספריית הזמן.

יְבוּא בקשות
יְבוּא זְמַן

צור רשימה של כתובות אתרים של התמונות שברצונך להוריד. תן להם להיות לפחות עשר כדי שתוכל להבחין בהבדל משמעותי בעת יישום הברגה.

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',
]

עברו בלולאה על הרשימה של כתובות URL שמורידות כל תמונה לאותה תיקייה המכילה את הפרויקט שלך. הצג את הזמן שנדרש להורדת התמונות על ידי הפחתת זמן הסיום משעת ההתחלה.

start_time = time.perf_counter()
ל img_url ב img_urls:
img_bytes = requests.get (img_url).content
img_name = img_url.split('/')[3]
img_name = ו'{img_name}.jpg'
עם פתח (img_name, 'wb') כפי ש img_file:
img_file.write (img_bytes)
הדפס(ו'{img_name} הורד...')
finish_time = time.perf_counter()
הדפס(f'סיים ב {finish_time - start_time} שניות')

לתוכנית לוקח בערך 22 שניות להוריד את 12 התמונות. זה עשוי להשתנות עבורך מכיוון שהזמן שלוקח להורדת התמונות תלוי גם במהירות האינטרנט שלך.

שנה את התוכנית לשימוש בהשרשור באמצעות מודול concurrent.features. במקום לולאה, השתמש בפונקציה. זו הפונקציה שתעביר ל- מוציא להורג למשל.

יְבוּא בקשות
יְבוּא זְמַן
יְבוּא 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הורדה_תמונה(img_url):
img_bytes = requests.get (img_url).content
img_name = img_url.split('/')[3]
img_name = ו'{img_name}.jpg'
עם פתח (img_name, 'wb') כפי ש img_file:
img_file.write (img_bytes)
הדפס(ו'{img_name} הורד...')

עם concurrent.futures. ThreadPoolExecutor() כפי ש מוציא להורג:
executor.map (download_image, img_urls)

finish_time = time.perf_counter()

הדפס(f'סיים ב {finish_time-start_time} שניות')

לאחר הצגת השרשור. הזמן מצטמצם משמעותית. זה לקח רק 4 שניות כדי להשלים את ביצוע התוכנית.

תרחישים מתאימים לשרשור

חלק מהתרחישים המתאימים לשרשור הם:

  • משימות הקשורות ל-I/O: אם התוכנית מבלה את רוב הזמן בהמתנה להשלמת פעולות הקלט או הפלט. השרשור יכול לשפר את הביצועים על ידי מתן אפשרות לביצוע משימות אחרות בזמן ההמתנה לסיום פעולות ה-I/O.
  • גירוד אינטרנט: גירוד אינטרנט כולל ביצוע בקשות HTTP וניתוח תגובות HTML. השרשור מסייע להאיץ את התהליך בכך שהוא מאפשר לך לבצע מספר בקשות בו זמנית.
  • משימות הקשורות למעבד: שרשור יכול לעזור בשיפור הביצועים על ידי מתן אפשרות לביצוע של משימות מרובות במקביל.

הכר את עצמך עם שרשור בשפות אחרות

Python היא לא השפה היחידה שתומכת בהשרשור. רוב שפות התכנות תומכות בצורה כלשהי של שרשור. חשוב להכיר את היישום של שרשורים בשפות אחרות. זה מצייד אותך במיומנויות הנדרשות להתמודדות עם תרחישים שונים שבהם שרשור עשוי לחול.