בכל רגע מסוים, רוב האנשים יתקלו בבעיה שתסקור כי סקריפט בסיסי של PowerShell פשוט נמשך יותר מדי זמן לפתור. זה עשוי להיות איסוף נתונים ממספר רב של מחשבים ברשת שלך או אולי יצירת המון משתמשים חדשים ב Active Directory בבת אחת. אלה הם דוגמאות מצוינות למקומות בהם שימוש בעוצמת העיבוד יאפשר לקוד שלך לרוץ במהירות יותר. בואו נתחיל לדבר על כיצד לפתור את זה באמצעות מרוצי תהליכות בפוורשל!
ההפעלה המוגדרת מראש של PowerShell היא בת של אשת חוט יחיד. היא מריצה פקודה אחת וכאשר היא מסיימת, היא מתקדמת לפקודה הבאה. זה נחמד מאוד מאחר והוא שומר על הרצה חוזרת של הכל ואינו משתמש במשאבים רבים. אבל מה קורה אם הפעולות שהיא בוצעת אינן תלויות זו בזו ויש לך משאבי מעבד נוספים? במקרה כזה, הגיע הזמן להתחיל לחשוב על מרוצי תהליכים.
במאמר זה, תלמד כיצד להבין ולהשתמש בטכניקות שונות של מרוצי תהליכים בפוורשל כדי לעבד זרמי נתונים מרובים באותו הזמן אך ניהול אותם דרך אותו מסוף.
הבנת מרוצי תהליכים בפוורשל
מריצת תהליכים מרובים בו זמן היא דרך להריץ יותר מאשר פקודה אחת בכל פעם. בזמן ש-PowerShell בדרך כלל משתמש בחוט יחיד, ישנן הרבה דרכים להשתמש ביותר מאשר זו כדי לפרלליזציה של הקוד שלך.
התועלת העיקרית של מרוצי התהליכים היא להפחית את זמן הריצה של הקוד. ההפחתה בזמן זה היא במחיר של דרישת הרבה מאוד משאבי מערכת. כאשר משתמשים במרוצי תהליכים, הרבה פעולות מתבצעות בו זמן, ולכן דורשת יותר מערכות משאבים.
לדוגמה, מה קורה אם תרצה ליצור משתמש חדש ב-Active Directory? בדוגמה זו, אין כל צורך ברצון לבצע מספר פעולות במקביל, מכיוון שרק פקודה אחת נכנסת לפועל. כל זה משתנה כאשר ברצונך ליצור 1000 משתמשים חדשים.
בלעדי רצון לבצע פעולות מרובות, יידרש להפעיל את הפקודה New-ADUser
אלף פעם כדי ליצור את כל המשתמשים. אולי יידרשו שלוש שניות ליצירת משתמש חדש. כדי ליצור את כל 1000 המשתמשים, ייקח כמעט שעה. במקום להשתמש בתהליך יחיד לאלף פקודות, ניתן להשתמש במאה תהליכים, כאשר כל תהליך מפעיל עשר פקודות. כעת, במקום לקחת כ-50 דקות, אתה מגיע למעט לדקה אחת!
שים לב שלא תראה התפשטות מושלמת. הפעולה של יצירה והשמדה של אובייקטים בקוד ייקחו זמן מסוים. בשימוש בתהליך יחיד, PowerShell יפעיל את הקוד וסיים. בשימוש בתהליכים מרובים, התהליך המקורי שמפעיל את הקונסול ישמש לניהול שאר התהליכים. בנקודה מסוימת, התהליך המקורי יגיע למקסימום ויהיה עסוק רק בניהול שאר התהליכים.
דרישות ראשוניות למקור פתיחת תהליכים ב-PowerShell
תלמד כיצד פתיחת תהליכים ב-PowerShell עובדת מעשית במאמר זה. אם תרצה להתקדם יחד, למטה ישנם כמה דברים שתצטרך ופרטים על הסביבה המשמשת.
- Windows גרסת PowerShell 3 או גבוהה יותר – למעט אם צוין אחרת, כל הקוד שיוצג יעבוד בגרסת Windows PowerShell 3 או גבוהה יותר. גרסת Windows PowerShell 5.1 תשמש לדוגמאות.
- מעבד וזיכרון פנויים – תצטרך לפחות קצת מעבד וזיכרון פנויים כדי למקבל עם PowerShell. אם אין לך את זה זמין, ייתכן שלא תראה כל יתרון בביצועים.
עדיפות מספר 1: תקן את הקוד שלך!
לפני שאתה צולל להאצת הסקריפטים שלך עם ריבוי תהליכים ב-PowerShell, יש כמה פעולות קדם עבודה שתרצה לבצע. ראשון הוא לשפר את הקוד שלך.
למרות שניתן להפעיל יותר משאבים על הקוד שלך כדי להפעיל אותו מהר יותר, ריבוי תהליכים מביא הרבה מורכבות נוספת. אם יש דרכים שבהן אתה יכול להאיץ את הקוד שלך לפני ריבוי תהליכים, זה צריך להיעשות קודם.
זיהוי נקודות חנק
אחד הצעדים הראשונים במקבולת הקוד שלך הוא לגלות מה מאט אותו. הקוד יכול להיות איטי בגלל לוגיקה לקויה או לולאות נוספות שבהן אתה יכול לבצע כמה שינויים כדי לאפשר ביצוע מהיר יותר לפני ריבוי תהליכים.
דוגמה נפוצה לאיך להאיץ את הקוד שלך היא להזיז את הסינון שלך שמאלה. אם אתה מתעסק עם הרבה נתונים, כל סינון שאתה רוצה לאפשר כדי להפחית את כמות הנתונים צריך להתבצע כמה שיותר מוקדם. להלן דוגמה לקוד לקבלת כמות ה-CPU שנמצאת בשימוש על ידי התהליך svchost.
הדוגמה למטה קוראת את כל התהליכים הרצים ואז מסננת תהליך יחיד (svchost). לאחר מכן מבחרת את מאפיין המעבד ומבטיחה שהערך לא ריק.
השווה את הקוד למעלה לדוגמה למטה. למטה דוגמה נוספת לקוד שמפיק את אותו פלט אך מאורגן בצורה שונה. שים לב שהקוד למטה פשוט יותר ומעביר את כל הלוגיקה האפשרית לשמאל מסימן הצינור. זה מונע מ־Get-Process
להחזיר תהליכים שאין לך עניין בהם.
למטה תוכל למצוא את ההבדל בזמן להרצת שני השורות למעלה. בעוד שההבדל של 117 מילישניות לא יובהר אם אתה רץ את הקוד רק פעם אחת, זמן ההרצה יתחיל להתאסף אם תריץ אותו אלפי פעמים.

שימוש בקוד בטוח מתח
למען האמת, ודא שהקוד שלך הוא "בטוח לתהליך". המונח "בטוח לתהליך" מתייחס לכך שאם תהליך אחד מריץ קוד, תהליך נוסף יכול לרוץ את אותו הקוד באותו זמן ולא יגרום להתנגשות.
לדוגמה, כתיבה לקובץ אותו בשני תהליכים שונים אינה בטוחה לתהליך מכיוון שהוא לא ידע מה להוסיף לקובץ תחילה. לעומת זאת, שני תהליכים שקוראים מקובץ הוא בטוח לתהליך מכיוון שהקובץ לא משתנה. שני התהליכים מקבלים את אותו הפלט.
הבעיה עם קוד PowerShell שבו רצועת מסרים שאינה בטוחה היא שיתכן שתקבל תוצאות לא עקביות. לפעמים זה עשוי לעבוד נכון בגלל שהרצת התהליכים פשוט תתאים נכון לא לגרום להתנגשויות. לפעמים נתקלים בהתנגשות וזה יקשה על תיקון הבעיה עקב השגיאות שאינן עקביות.
אם אתה מפעיל רק שניים או שלושה עבודות בכל פעם, ייתכן והן יקרו די בדיוק כך שהן יכתבו לקובץ בזמנים שונים. כאשר אתה מגדיל את הקוד ל-20 או 30 עבודות, הסיכוי שלא פחות משתיים מהעבודות ינסו לכתוב באותו הזמן יורד במשמעותיות.
ביצוע מקביל עם PSJobs
אחת מהדרכים הקלות ביותר ליצור רקע רב-תהליך בסקריפט היא עם PSJobs. PSJobs מגיעות עם cmdlets שמובנים במודול Microsoft.PowerShell.Core. המודול Microsoft.PowerShell.Core כלול בכל הגרסאות של PowerShell מגרסה 3 ומעלה. פקודות במודול זה מאפשרות לך להריץ קוד ברקע תוך המשך הרצת קוד שונה ב foreground. תוכל לראות את כל הפקודות הזמינות למטה.

מעקב אחרי העבודות שלך
כל ה-PSJobs נמצאות באחד מ-אחת עשרה מצבים. אלו הם המצבים שבהם PowerShell ניהלת את העבודות.
מתחת לך תמצא רשימה של המצבים הנפוצים ביותר שבהם עבודה יכולה להימצא.
- הושלם – העבודה הושלמה וניתן לאחזר את נתוני הפלט או להסיר את העבודה.
- פועל – העבודה פועלת כרגע ואין אפשרות להסיר אותה ללא עצירת כוח. נתוני הפלט גם אינם יכולים להיאחזר כרגע.
- חסום – העבודה עדיין רצה, אך המארח נדרש לספק מידע לפני שהיא יכולה להמשיך.
- נכשל – התרחשה שגיאה מסיימת במהלך ביצוע העבודה.
כדי לקבל את מצב העבודה שהחלה, עליך להשתמש בפקודת Get-Job
. פקודה זו מביאה את כל התכונות של העבודות שלך.
להלן הפלט עבור עבודה בה אתה יכול לראות שהמצב הוא הושלם. הדוגמה למטה מבצעת את הקוד Start-Sleep 5
בתוך עבודה באמצעות פקודת Start-Job
. מצב העבודה הוא לאחר מכן מוחזר באמצעות פקודת Get-Job
.

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

יצירת עבודות חדשות
כפי שראית למעלה, פקודת Start-Job
מאפשרת לך ליצור עבודה חדשה שמתחילה לבצע קוד בעבודה. כאשר אתה יוצר עבודה, אתה מספק קופסת תסריט שמשמשת לעבודה. PSJob מייצר אז עבודה עם מספר זיהוי ייחודי ומתחיל להריץ את העבודה.
היתרון העיקרי כאן הוא שזה לוקח פחות זמן להפעיל את הפקודה Start-Job
מאשר להפעיל את ה- scriptblock שאנו משתמשים בו. ניתן לראות בתמונה למטה שבמקום שהפקודה לוקחת חמישה שניות להשלים, לקחתה רק .15 שניות להתחיל את העבודה.

הסיבה שהצליח להפעיל את אותו קוד בפועל של הזמן הייתה כי הוא התריע ברקע כ- PSJob. לקחתה .15 שניות להתקין ולהתחיל להפעיל את הקוד ברקע במקום להפעיל אותו בפועל ולהישנות לחמישה שניות.
אחזור פלט העבודה
לעיתים הקוד בתוך ה- job מחזיר פלט. ניתן לאחזר את הפלט של קוד זה באמצעות פקודת Receive-Job
. פקודת Receive-Job
מקבלת PSJob כקלט ואז כותבת את פלט העבודה לקונסול. כל דבר שיצא מהעבודה במהלך ההפעלה שלה נשמר כך שכאשר העבודה נאחזת, היא מחזירה את כל מה שנשמר באותו זמן.
דוגמה לכך היא הפעלת הקוד למטה. זה ייצור ויפעיל עבודה שתכתוב Hello World לפלט. זורק את הפלט מהעבודה ומציג אותו בקונסול.

יצירת עבודות מתוזמנות
דרך נוספת שבה ניתן להתקשר עם PSJobs היא דרך עבודה מתוזמנת. עבודות מתוזמנות דומות למשימה מתוזמנת של Windows שניתן להגדיר בעזרת מתזמן משימות. עבודות מתוזמנות יוצרות אפשרות לתזמן בקלות במשימה מתוזמנת קובץ תסריטים מורכב של PowerShell. באמצעות עבודה מתוזמנת, ניתן להפעיל PSJob ברקע בהתבסס על מפעילים.
פקעי עבודה
פקעי העבודה יכולים להיות דברים כמו זמן ספציפי, כאשר משתמש נכנס למערכת, כאשר המערכת מאתחלת ועוד. ניתן גם להפעיל את הפקעים לפי תקופות זמן. כל המפעילים הללו מוגדרים בעזרת פקודת New-JobTrigger
. הפקודה הזו משמשת לציין מפעיל שיריץ את העבודה המתוזמנת. עבודה מתוזמנת ללא מפעיל חייבת להיפעל ידנית, אך כל עבודה יכולה לכלול מספר מפעילים.
בנוסף לקיום מפעיל, עליך עדיין להשתמש בבלוק תסריט כמו ב-PSJob רגיל. לאחר שיש לך גם את המפעיל ואת בלוק התסריט, עליך להשתמש בפקודת Register-ScheduledJob
כדי ליצור את העבודה כמו שמוצג בקטע הבא. הפקודה הזו משמשת לציין מאפיינים של העבודה המתוזמנת כמו הבלוק של התסריט שיתבצע והמפעילים שנוצרים באמצעות פקודת New-JobTrigger
.
דוגמה
אולי תזדקק לקוד PowerShell להרצתו בכל פעם שמישהו מתחבר למחשב. ניתן ליצור עבודה מתוזמנת עבור זה.
על מנת לבצע זאת, תגדיר תחילה טריגר באמצעות New-JobTrigger
ותגדיר את המשימה המתוזמנת כמו שמוצג למטה. משימה זו תכתוב שורה לקובץ לוג בכל פעם שמישהו נכנס.
פעם שתריץ את הפקודות למעלה, תקבל פלט דומה לזה שמתקבל ביצירת משימה חדשה, המציגה את מזהה המשימה, הבלוק של הסקריפט ומאפיינים נוספים כמו שמוצג למטה.

לאחר מספר ניסיונות להתחבר, ניתן לראות מהתמונה למטה שהיא רושמת את הניסיונות.

מפעיל את הפרמטר AsJob
דרך נוספת להשתמש במשימות היא להשתמש בפרמטר AsJob
שכלול בהרבה מפקודות PowerShell. בשל קיומם של הרבה פקודות שונות, אפשר למצוא אותן כולן באמצעות Get-Command
כפי שמוצג למטה.
אחת מהפקודות השכיחות ביותר היא Invoke-Command
. לרוב, כאשר אתה מפעיל פקודה זו, היא מתחילה לבצע פקודה מיידית. בעוד שחלק מהפקודות יחזירו מיד, מאפשרות לך להמשיך עם מה שאתה עושה, חלקן יחכו עד שהפקודה תסתיים.
שימוש בפרמטר AsJob
עושה בדיוק את מה שנשמע ומפעיל את הפקודה באופן חיצוני כמשימה במקום להרץ אותה באופן סינכרוני במקובל.
למרות שברוב הזמן ניתן להשתמש ב-AsJob
עם המכונה המקומית, Invoke-Command
אין לו אפשרות פנימית להריץ על המכונה המקומית. יש פתרון מגרה על ידי שימוש ב-Localhost כערך לפרמטר ComputerName
כפי שמוצג בדוגמה למטה.
על מנת להציג את הפרמטר AsJob
בפעולה, בדוגמה למטה משתמשת ב- Invoke-Command
כדי להשהות לפרק של חמישה שניות ולאחר מכן לחזור על אותו הפקודה באמצעות AsJob
כדי להציג את ההבחנה בזמני הביצוע.

Runspaces: כמו עבודות אך מהירות יותר!
עד כה, למדת על דרכים להשתמש בטרדים נוספים עם PowerShell רק באמצעות הפקודות המובנות. אפשרות נוספת להפוך את הסקריפט שלך למרובה-תהליך היא להשתמש במרחב ריצה נפרד.
Runspaces הם האזור הסגור שבו התהליכים שרצים עם PowerShell פועלים בו. בעוד שהמרחב שישמש עם מסוף ה- PowerShell מוגבל לתהליך יחיד, תוכל להשתמש במרחבי ריצה נוספים כדי לאפשר שימוש בתהליכים נוספים.
מרחב ריצה נגד PSJobs
בעוד שמרחב ריצה ו- PSJob חולקים הרבה דמויות, ישנם הבדלים גדולים בביצועים. ההבדל הגדול ביותר בין מרחבי ריצה ו- PSJobs הוא הזמן שנדרש להקצאתם ופירוקם כל פעם.
בדוגמה מהקטע הקודם, יצירת ה- PSJob לקחה כ-150 מילישניות להתחיל. זהו בערך המקרה הטוב ביותר, מאחר וה- scriptblock לעבודה לא כלל קוד רב ולא היו יותר מדי משתנים נוספים שמועברים לעבודה.
בניגוד ליצירת ה- PSJob, מרחב הריצה נוצר מראש. רוב הזמן שנדרש להפעיל עבודת מרחב נטמע לפני שנוסף קוד לעבודה.
למטה דוגמה להפעלת אותה הפקודה שהשתמשנו בה ל- PSJob, אך הפעם במרחב ריצה.

בניגוד, למטה נמצא הקוד המשמש לגרסת הראנספייס. ניתן לראות שיש יותר קוד כדי לבצע את אותה המשימה. אך היתרון של הקוד הנוסף מורגש בכך שהוא חותך כמעט 3/4 מהזמן המוצרך, מאפשר לפקודה להתחיל לרוץ ב-36 מילישניות לעומת 148 מילישניות.

הרצת ראנספייס: הדרכה
שימוש בראנספייס עשוי להיות משימה מסובכת בתחילתה מאחר שאין עוד פקודות PowerShell שמכוונות. עליך להתמודד ישירות עם מחלקות .NET. בסעיף זה, ננסח מהו נדרש ליצירת ראנספייס בפוורשל.
בדרך זו, תיצור ראנספייס נפרד מקונסולת ה-PowerShell שלך ומופע PowerShell נפרד. לאחר מכן, תשייך את הראנספייס החדש למופע ה-PowerShell החדש ותוסיף קוד למופע זה.
יצירת הראנספייס
הדבר הראשון שעליך לעשות הוא ליצור את הראנספייס החדש שלך. תעשה זאת באמצעות מחלקת runspacefactory
. נשמור זאת למשתנה, כמו שמוצג למטה, כך שיהיה ניתן להתייחס אליו מאוחר יותר.
עכשיו שהראנספייס נוצר, נשייך אותו למופע של PowerShell כדי להריץ קוד PowerShell. לכך, נשתמש במחלקת powershell
ובדומה לראנספייס, נצטרך לשמור את זה למשתנה כמו שמוצג למטה.
לאחר מכן, נוסיף את הראנספייס למופע שלך של PowerShell, נפתח את הראנספייס כדי להריץ קוד ונוסיף את ה- scriptblock שלך. הדבר מוצג למטה עם scriptblock לשינה של חמישה שניות.
ביצוע הראנספייס
עד כה, לא הופעל קטע הסקריפט. כל מה שנעשה עד כה הוא להגדיר הכל עבור ה־runspace. כדי להתחיל להפעיל את קטע הסקריפט, יש לך שתי אפשרויות.
- Invoke() – השיטה
Invoke()
מפעילה את קטע הסקריפט ב־runspace, אך היא ממתינה לחזרה למסוף עד שה־runspace מחזיר. זה טוב לבדיקה כדי לוודא שהקוד שלך מבוצע כראוי לפני שמשחררים אותו. - BeginInvoke() – בשימוש בשיטת
BeginInvoke()
זה מה שתרצה לראות באמת על מנת לראות תועלת בביצוע. זה יתחיל להריץ את קטע הסקריפט ב־runspace ומיד יחזיר אותך למסוף.
כאשר משתמשים ב־BeginInvoke()
, יש לאחסן את הפלט במשתנה מאחר שיהיה נחוץ לראות את מצב קטע הסקריפט ב־runspace כפי שמוצג למטה.
פעם שיש לך את הפלט מ־BeginInvoke()
מאוחסן במשתנה, ניתן לבדוק את המשתנה הזה כדי לראות את מצב העבודה כפי שמוצג למטה במאפיין IsCompleted
.

סיבה נוספת לכך שיהיה עליך לאחסן את הפלט במשתנה היא מכיוון שבניגוד לשיטת Invoke()
, BeginInvoke()
לא תחזיר אוטומטית את הפלט כאשר הקוד מסתיים. כדי לעשות זאת, עליך להשתמש בשיטת EndInvoke()
פעם שהיא הושלמה.
בדוגמה זו, לא יהיה פלט אך כדי לסיים את הקריאה, יש להשתמש בפקודה הבאה.
לאחר שכל המשימות שהוספת למרחב הריצה הושלמו, יש לסגור תמיד את המרחב הריצה. פעולה זו תאפשר לתהליך איסוף הזבל של PowerShell לנקות משאבים שאינם בשימוש. למטה הפקודה שתשתמש בה לסגירת המרחב הריצה.
שימוש בבריכות מרחבי ריצה
למרובע הוא שיפור בביצועים, אך הוא נתקל בהגבלה עיקרית של תהליך יחיד. זהו המקום בו בריכות המרחבי ריצה מתבלות בשימושם במספר תהליכים.
בקטע הקודם, השתמשת רק בשני מרחבי ריצה. השתמשת ברצף אחד עבור מסוף PowerShell עצמו ועוד רצף שיצרת באופן ידני. בריכות המרחבי ריצה מאפשרות לך לנהל מספר מרחבי ריצה ברקע באמצעות משתנה יחיד.
התנהגות זו של מרחבי ריצה מרובים ניתנת לביצוע גם עם אובייקטים מרחב ריצה מרובים, אך שימוש בבריכת מרחבי ריצה הופך את הניהול לקל יותר.
בריכות מרחבי ריצה שונות ממרחבי ריצה יחידים באופן שהן מוגדרות. אחת ההבחנות המרכזיות היא שאתה מגדיר את כמות התהליכים המרבית שיכולים לשמש בבריכת המרחבים. עם מרחב ריצה יחיד, הוא מוגבל לתהליך יחיד, אך עם בריכה, אתה צובע את מספר התהליכים המרבי שבו יכולה הבריכה להתרחש.
כמות התהליכים המומלצת בבריכת מרחבי ריצה תלויה במספר המשימות שבוצעות ובמחשב שבו נרצה להריץ את הקוד. בזמן שהגדלת הכמות המקסימלית של התהליכים לא תשפיע באופן שלילי על המהירות ברוב המקרים, יתכן גם שלא תראה תועלת.
הדגמת מהירות בריכת מרחבי ריצה
להציג מקרה שבו בריכת מרחב הרצה תגביר על מרחב הרצה יחיד, אולי תרצה ליצור עשרה קבצים חדשים. אם היית משתמש במרחב הרצה יחיד למשימה זו, היית יוצר את הקובץ הראשון, ואז היית ממשיך לשני, ואז לשלישי, וכן הלאה עד שכל העשרה היו נוצרים. הסקריפט לדוגמה עבור משימה זו עשוי להיראות כך. תיתן לסקריפט הזה עשרה שמות קבצים בלולאה וכולם יינוצרו.
בדוגמה למטה, מוגדר בלוק סקריפט שמכיל סקריפט קצר המקבל שם ויוצר קובץ עם השם הזה. מרחב מרחב הרצה נוצר עם מקסימום של 5 תהליכים.
לאחר מכן, לולאה תמצבע עשר פעמים ובכל פעם תשמש את מספר ההרצה במשתנה $_
. אז זה יהיה 1 בהרצה הראשונה, 2 בהרצה השנייה וכן הלאה.
הלולאה תיצור אובייקט PowerShell, תקצוב את בלוק הסקריפט, ואת הארגומנט לסקריפט ותתחיל את התהליך.
לבסוף, בסוף הלולאה, היא תמתין שכל משימות התור לסיום.
עכשיו במקום ליצור תהליכים אחד אחר זה, יוצרים חמישה בכל פעם. ללא בריכות מרחב הרצה, היית צריך ליצור ולנהל חמישה מרחבי ריצה נפרדים וחמישה הרצות פוורשל נפרדות. ניהול זה מהר מתהפך לבלגן.
במקום זאת, ניתן ליצור בריכת מרחבי ריצה, הרצת פוורשל, להשתמש באותו בלוק קוד ובאותה לולאה. ההבדל הוא שהמרחב יגדיל את עצמו כדי להשתמש בכל חמישה מהתהליכים הללו לבד.
יצירת בריכות מרחבי ריצה
יצירת קבוצת ראנספייס היא דומה מאוד לראנספייס שנוצר בקטע קודם. למטה נמצא דוגמא כיצד לעשות זאת. הוספת סקריפטבלוק וההפעלה היא זהה לראנספייס. כפי שניתן לראות למטה, יש יצירת קבוצת ראנספייס עם מרבית חמישה תהליכים.
השוואת ראנספייס וקבוצות ראנספייס לצורך מהירות
כדי להראות את ההבחנה בין ראנספייס לקבוצת ראנספייס, צור ראנספייס והפעל את פקודת Start-Sleep
מהשורה הקודמת. הפעם, אף על פי שזה צריך לרוץ 10 פעמים. כפי שניתן לראות בקוד למטה, יש יצירת ראנספייס שישנה שתירד 5 שניות.
שים לב שבעקבות שימוש בראנספייס יחיד, עליך להמתין עד שהוא יסתיים לפני שהפעלה נוספת יכולה להתחיל. לכן נוסף שינת ישנה המתנה של 100 מילישניות עד שהמשימה תושלם. בעוד זה יכול להיות נמוך, תראה התראות נמוכות יותר כי יהיה עליך לבדוק אם המשימה נגמרה מאשר לחכות לסיום המשימה.
מהדוגמא למטה, ניתן לראות שנדרשו כ-51 שניות להשלימו של 10 סטים של 5 שניות של שינת הראנספייס.

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

למטה ניתן לראות סיכום של ההבחנה בין ראנספייס לקבוצת ראנספייס בדוגמאות אלו.
Property | Runspace | Runspace Pool |
---|---|---|
Wait Delay | Waiting for each job to finish before continuing to the next. | Starting all of the jobs and then waiting until they have all finished. |
Amount of Threads | One | Five |
Runtime | 50.8 Seconds | 10.1 Seconds |
Easing into Runspaces with PoshRSJob
A frequent occurrence when programming is that you will do what is more comfortable and accept the small loss in performance. This could be because it makes the code easier to write or easier to read, or it could just be your preference.
דבר זה קורה גם עם PowerShell, בו ישנם אנשים שיעדיפו להשתמש ב-PSJobs במקום בראנספייסים בשל קלות השימוש בהם. ישנם כמה דברים שניתן לעשות כדי לחלק את ההבדל ולקבל את הביצועים הטובים יותר ללא קשיים נוספים מדי.
ישנה יחידה מובילה בתחום נקראת PoshRSJob שמכילה מודולים המתאימים לסגנון של PSJobs רגילים אך עם היתרון הנוסף של שימוש בראנספייסים. במקום לציין את כל הקוד ליצירת הראנספייס ואובייקט הפאוושל, מודול ה-PoshRSJob טופלת בכל זה בזמן ביצוע הפקודות.
כדי להתקין את המודול, הפעל את הפקודה למטה בשולי הפושע בסשן PowerShell ברמת ניהול.
ברגע שהמודול מותקן, ניתן לראות שהפקודות זהות לפקודות ה-PSJob עם תחילית RS. במקום Start-Job
יש Start-RSJob
. במקום Get-Job
יש Get-RSJob
.
למטה דוגמה של איך להריץ את אותו הפקודה עם PSJob ושוב עם RSJob. כפי שניתן לראות, הם מציינים סינטקס ופלט דומים מאוד, אך הם אינם מותאמים לחלוטין.

למטה קטע קוד שניתן להשתמש בו להשוואת ההבדל במהירות בין PSJob ו-RSJob.
כפי שניתן לראות למטה, יש הבדל משמעותי במהירות מאחר וה-RSJobs עדיין משתמשים בראנספייסים מתחת לכיסאות.

Foreach-Object -Parallel
הקהילה של PowerShell מתאמצת כבר מזמן למצוא דרך פשוטה ומובנית יותר לעשות multithreading במהירות. המתג הפרללי הוא מה שיצא מזה.
עד כה, בעת כתיבת זה, PowerShell 7 עדיין בתצורה מקדימה, אך הם הוסיפו פרמטר בשם `Parallel` לפקודת `Foreach-Object`. התהליך הזה משתמש ב-runspaces כדי לעשות את הקוד multithreaded ומשתמש ב-scriptblock המשמש ל־`Foreach-Object` כ-scriptblock עבור ה-runspace.
עוד לא הוסכם על הפרטים, אך ייתכן כי זה יהיה דרך פשוטה יותר להשתמש ב-runspaces בעתיד. כפי שניתן לראות למטה, ניתן לעבור במהירות על מספר רב של סטים של sleep.

אתגרים עם מרובה תהליכים
בעוד ש-multithreading נשמע כמשהו מדהים עד כה, זה לא בדיוק המצב. ישנם הרבה אתגרים שמתגלים בעקבות multithreading של כל קוד.
שימוש במשתנים
אחד האתגרים הגדולים והברורים ביותר עם multithreading הוא שאי אפשר לשתף משתנים בלי להעביר אותם כארגומנטים. יש יוצא מן הכלל של hashtable מסונכרנית, אך זהו נושא לשיחה אחרת.
שני הפתרונות, PSJobs ו-runspaces, פועלים בלי גישה למשתנים קיימים ואין דרך להתמודד עם משתנים שנמצאים ב-runspaces שונים מהקונסול שלך.
זה מהווה אתגר עצום להעברת מידע בצורה דינמית לעבודות אלו. התשובה שונה לפי סוג ה-multithreading שבו אתה משתמש.
עבור Start-Job
ו־Start-RSJob
מהמודול PoshRSJob, ניתן להשתמש בפרמטר ArgumentList
כדי לספק רשימת אובייקטים שיעברו כפרמטרים ל־scriptblock בסדר שמציינים. להלן דוגמאות לפקודות המשמשות עבור PSJobs ו־RSJobs.
PSJob:
RSJob:
קיומם של מרחבי ריצה טבעיים לא מעניק לך את אותו קלות. במקום זאת, עליך להשתמש בשיטת AddArgument()
על אובייקט PowerShell. להלן דוגמא לכיצד זה ייראה עבור כל אחד.
מרחב ריצה:
בעוד שבריכות מרחבי ריצה פועלות באותו אופן, להלן דוגמא כיצד להוסיף ארגומנט לבריכת מרחבי ריצה.
יומן
העבודה ברב־ת־לוקאליות מביאה גם לאתגרי יומן. מאחר וכל תהליך פועל באופן עצמאי מהשאר, לא כלם יכולים להתחבר לאותו מקום. אם ניסית להגיב לקובץ אחד עם מספר תהליכים, בכל פעם שתהליך אחד יכתוב לקובץ, לא יהיה ניתן לתהליכים אחרים לעשות זאת. זה עשוי להאט את הקוד שלך, או אפילו לגרום לו להפסיק לעבוד.
כדי להמחק על כך, להלן קטע קוד לניסיון להגיב 100 פעמים לקובץ יחיד באמצעות 5 תהליכים בבריכת מרחבי ריצה.
מהפלט אתה לא תראה שום שגיאות, אך אם תבדוק את גודל קובץ הטקסט, תוכל לראות שלא כל ה-100 עבודות סיימו בהצלחה.

אחת הדרכים להתמודד עם זה היא להגיב לקבצים נפרדים. זה מסיר את בעיית נעילת הקובץ, אך אז יש לך הרבה קבצי יומן שעליך לסדר דרכם כדי להבין מה קרה.
עוד אפשרות היא שתאפשר לך להתעלם מהזמנים של חלק מהפלט ולרשום רק מה שהעבודה עשתה כאשר היא הסתיימה. זה מאפשר לך להכליל הכול דרך הסשן המקורי שלך, אך אתה מאבד חלק מהפרטים מאחר ואינך בהכרח יודע באיזו סדר התרחשו הכל.
סיכום
בעוד שספירות מרובות יכולות לספק רווחי ביצועים עצומים, הן יכולות גם לגרום לכאבי ראש. בעוד שחלק מעומסי העבודה ייהנו מהיתרונות באופן רב, אחרים לא ייהנו בכלל. ישנם יתרונות וחסרונות רבים בשימוש בספירה מרובה, אך אם משתמשים בה בצורה נכונה, ניתן להפחית באופן משמעותי את זמן הריצה של הקוד שלך.
קריאה נוספת
Source:
https://adamtheautomator.com/powershell-multithreading/