כיצד להשתמש ב- cProfile לפרופיל קוד פייתון

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

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

כיצד להשתמש ב- cProfile

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

הנה דוגמה לצעצועים לשימוש cProfile:

def להוסיף (x, y): x + = str (y) להחזיר x def add_2 (x, y): אם y% 20000 == 0: z = [] עבור q בטווח (0,400000): z.append ( q) def main (): a = [] עבור n בטווח (0,200000): add (a, n) add_2 (a, n) if __name__ == '__main__': יבוא cProfile cProfile.run ('main ( ) ') 

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

הפעל את הדוגמה הנ"ל ותתקבל במשהו כמו הפלט הבא:

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

  • בחלק העליון (השורה הראשונה בכחול), אנו רואים את המספר הכולל של השיחות שבוצעו בתוכנית המוגדרת ואת זמן הביצוע הכולל. ייתכן שתראה גם איור ל"שיחות פרימיטיביות ", כלומר שיחות לא-רקורסיביות , או שיחות המתבצעות ישירות לפונקציה שלא בתורן מכנות את עצמן בהמשך ערימת השיחות.
  • ncalls : מספר השיחות שבוצעו. אם אתה רואה שני מספרים מופרדים על ידי קו נטוי, המספר השני הוא מספר הקריאות הפרימיטיביות עבור פונקציה זו.
  • tottime : זמן הבילוי הכולל בפונקציה, לא כולל שיחות לפונקציות אחרות.
  • percall : זמן ממוצע לשיחה לטווח זמן , נגזר על ידי לקיחת זמן של זמן ולחלק אותו לפי שיחות nc .
  • cumtime : סה"כ זמן בילה את הפונקציה, לרבות שיחות לפונקציות אחרות.
  • percall (מספר 2): זמן ממוצע לשיחה לזמן מועד ( זמן מחולק ל- ncalls ).
  • שם קובץ: lineno : שם הקובץ, מספר השורה ושם הפונקציה של השיחה המדוברת.

כיצד לשנות דוחות cProfile

כברירת מחדל, cProfileממיין את הפלט שלו לפי "שם סטנדרטי", כלומר הוא ממיין לפי הטקסט בעמודה הימנית הקיצונית (שם קובץ, מספר שורה וכו ').

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

אנו יכולים לייצר תוצאות אלה על ידי הפעלת  cProfile קצת אחרת. שים לב כיצד ניתן לעבד מחדש את החלק התחתון של התוכנית הנ"ל כדי למיין את הנתונים הסטטיסטיים לפי עמודה אחרת (במקרה זה ncalls):

אם __name__ == '__main__': ייבא cProfile, pstats profiler = cProfile.Profile () profiler.enable () main () profiler.disable () stats = pstats.Stats (profiler) .sort_stats ('ncalls') stats.print_stats () 

התוצאות ייראו בערך כך:

כך כל זה עובד:

  • במקום לבצע פקודה דרך cProfile.run(), וזה לא מאוד גמיש, אנו יוצרים פרופילי אובייקט , profiler.
  • כאשר אנו רוצים לפרופיל פעולה כלשהי, אנו קוראים תחילה .enable()למופע של אובייקט פרופיל, ואז מריצים את הפעולה ואז מתקשרים .disable(). (זוהי דרך אחת לפרופיל רק חלק מתוכנית).
  • pstatsמודול משמש כדי לתפעל את התוצאות שנאספו על ידי אובייקט Profiler ולהדפיס את התוצאות האלה.

שילוב של אובייקט פרופיל pstatsומאפשר לנו לתפעל את נתוני הפרופיל שנתפסו - למשל למיין את הסטטיסטיקה שנוצרה באופן שונה. בדוגמה זו, שימוש .sort_stats('ncalls')ממיין את הסטטיסטיקה לפי ncallsהעמודה. אפשרויות מיון אחרות זמינות.

כיצד להשתמש בתוצאות cProfile לאופטימיזציה

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

ncalls

המידע הראשון והמשמעותי ביותר cProfileשאיתו תוכלו לחשוף הוא אילו פונקציות נקראות בתדירות הגבוהה ביותר, באמצעות ncallsהעמודה.

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

בדוגמה שלעיל, הפונקציה add(והפונקציה add_2) נקראות שוב ושוב בלולאה. העברת הלולאה addלפונקציה עצמה, או הטמעת addהפונקציה לחלוטין, תפתור בעיה זו.

tottime

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

בדוגמה שלעיל, add_2הפונקציה משתמשת בלולאה כדי לדמות חישוב יקר כלשהו, ​​שדוחף את tottimeהציון שלו לראש. כל פונקציה עם tottimeציון גבוה ראויה למבט מקרוב, במיוחד אם היא נקראת פעמים רבות או בלולאה הדוקה.

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

כיצד לייצא נתוני cProfile

אם ברצונך להשתמש cProfileבסטטיסטיקה שנוצרה בדרכים מתקדמות יותר, תוכל לייצא אותם לקובץ נתונים:

stats = pstats.Stats (פרופיל) stats.dump_stats ('/ path / to / stats_file.dat') 

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

  • pyprof2calltreeמציג ויזואליזציות מפורטות של גרף השיחות של התוכנית וסטטיסטיקות השימוש מנתוני הפרופיל. מאמר זה מספק דוגמה מפורטת בעולם האמיתי לשימוש בו.
  • snakevizגם יוצר ויזואליזציות cProfileמנתונים, אך משתמש בייצוג שונה לנתונים - גרף "שמש" ולא גרף הלהבה של pyprof2calltree.

מעבר ל- cProfile עבור פרופילי פיתון

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

פרויקט אחד py-spy,, בונה פרופיל ליישום Python על ידי דגימה של פעילות השיחה שלו. py-spyניתן לבחון יישום פייתון פועל מבלי להפסיק ולהפעיל אותו מחדש, ומבלי לשנות את בסיס הקוד שלו, כך שהוא יכול לשמש לפרופיל יישומים פרוסים. py-spyגם מייצר קצת נתונים סטטיסטיים לגבי התקורה שנגרמה לזמן הריצה של פייתון (למשל, תקורה לאיסוף אשפה), cProfileשלא.