April 21, 2024

קוד אופטימלי - כמה מחשבות

ייעול קוד

מכירים אתרים איטיים?
תוכנות שבקושי זזות?
או יותר גרוע - אנימציות טעינה תקועות -

זה לרוב קורה בגלל קוד לא יעיל או תהליכים ארוכים!

איך נדע מתי צריך לייעל את הקוד

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

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

יש פה משהו נסתר - מתי אתם צריכים לייעל את הקוד?
כשאתם שמים לב!
כל עוד התוכנה עובדת מהר מספיק ואף אחד לא מתלונן - האם אתם צריכים לייעל?

אסטרטגיות ייעול בקוד ביצועים גבוה

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

אסטרטגיה 1 - אי אפשר לשפר את מה שאי אפשר למדוד

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

אז איך אנחנו מודדים?

קופסה שחורה

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

אתם מוזמנים לנסות את זה באתרים ואפליקציות שאתם מכירים!

בעזרת אילו כלים נמדוד כאן?

נמדוד בכלים שהם ב-High level כגון:

  • לוגים
  • דשבורדים
  • חישובים עצמאיים

קופסה לבנה

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

יש מגוון כלים למדידה כאן.

Chrome dev tools

https://developer.chrome.com/docs/devtools/performance/reference

Microsoft Visual Studio profiling

https://learn.microsoft.com/en-us/visualstudio/profiling/hot-path-to-root?view=vs-2022

C# .Net benchmark

https://github.com/dotnet/BenchmarkDotNet

golang benchmark

https://blog.logrocket.com/benchmarking-golang-improve-function-performance/

C++ Benchmarks

https://quick-bench.com/

אסטרטגיה 2 - שכתוב מערכות

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

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

כך או כך אתם תמצאו את עצמכם משכתבים את המערכת ומעצבים אותה מחדש.

  • שכתוב חלק מהפונקציות לשפה יעילה יותר, כמו שכתוב ספריות פייתון ב-C++.
  • שימוש בכלים מתקדמים יותר כמו מסדי נתונים חדשים או שימוש במערכות תורים.
  • עדכון גרסאות לטכנולוגיות ישנות כמו מעבר מדוטנט 4.5 לדוטנט החדש.

אסטרטגיה 3 - לרדת לרמה נמוכה יותר

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

זה כולל:

  • הכרת החומרה שאתם משתמשים בה.
    האם זה בקר? האם זה מחשב? מהי מערכת ההפעלה שאתם מפתחים עבורה?
    פיתוח בלינוקס או ווינדוס יכול להיות נקודת מפנה עבור ביצועי התוכנה שלכם.
  • האם המערכת תומכת מקביליות?
    כמה מעבדים יש, האם ניתן להריץ את התוכנה גם על כרטיסים גראפיים?
  • הכרת אסמבלי, פסיקות ואיך המעבד עובד.
    להכיר את השטיקים של מעבדים יכול לגרום לכם לחשוב מעבר לקוד עילי על מנת להשתמש בכלים שהמעבד נותן.
    כמו לדאוג שמשתמשים בפסיקות חכמות, או לדאוג שהזיכרון המוקצה בתוכנה מותאם לגודל הזיכרון מטמון.
    אופטימיזציה קלאסית היא להתאים את הזיכרון לכפולות של 2.
    למשל גדלי תמונה - במקום לייצר תמונות בגדלים שונים, תייצר תמונות בכפולות של 2.
    16,32,64,128 וכדו’…

דוגמא לאופטימזציה - הקצאות זיכרון

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

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

זה יכלול הקצאות והעתקה של זיכרון.

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

  • הקצאות גדלים של קבצים גדולים יכולים גם לקחת זמן וגם לקחת מקום.
    במחשבים “חלשים” יותר זה ההפך יכול לגרוע.
    אולם - הקצאות מרובות של זיכרון זה גם לא משהו טוב ולכן הפתרון של הקצאה אחת בזיכרון רציף היא עדיפה בהרבה.

זה שיפר את הקוד כמעט פי 2 או 3!


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

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

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

תודה על הקריאה!

על הפוסט

הפוסט נכתב על ידי Ilya, רישיון על ידי CC BY-NC-ND 4.0.

שתפו את הפוסט

Email Facebook Linkedin Print

קנו לי קפה

#Software