על מהירות, וזיכרון בין השיטות generators, list comprehension ופונקציות רגילות

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

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

א. מדוע ב the list comprehension method כאשר אני מבצע השמה למשתנה (X = list(people_interator)) הזיכרון של המערכת קופץ ישר לMB300 כאילו אני משתמש במתודה הראשונה. על פניו זה נשמע הגיוני כי אני שומר במערכת זיכרון רב, אולם מצד שני אם אני בוחר לעשות הדפסה לאותה רשימה, פעולה שמשאירה אותי עם זיכרון נמוך מאוד, אני מקבל את כל הערכים בבת אחת, וזה כאשר הgenerator כבר לא יכול להוציא עוד ערכים. ועל פניו נראה שאם אני מקבל את כל הערכים בבת אחת זה אומר שהם שמורים איפשהו במחשב לא כן? אבל אם ככה מדוע לא מופיעה במצב כזה הקפיצה בזיכרון. הסתירה כאן לא ברורה לי.

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

ב. שאלה זו קשורה במעט לסעיף א. כאשר אני עושה list comprehension איפה נשמר המידע עד שהפעולה נגמרת, הרי כל הרעיון בgenerator שכל פעם עובדים על פיסת מידע חדשה והקודמת נדרסת?
לצורך העניין יש לי רצון לספור תווים לתוך מילון ואין לי רצון להכניס ערכים שכבר הכנסתי כיצד אני עושה זאת?
הקוד הבא ירוץ לי שלוש פעמים במקום פעמיים. ולהוסיף if letter not in word_dic לא עושה את העבודה כי מבחינת המחשב לא הוכנסו הערכים עדיין למילון.
פתרון אלגנטי שראיתי הוא להוריד את התנאי ואת המילון הריק ואת זה להכניס ללולאה set(word)

'word = 'aba
word_dic = {}
word_dic = {letter : word.count(letter) for letter in word  if letter not in word_dic}

תודה ענקית למי שמתייחס :slight_smile:

the original method

Memory (Before): [18.285] Mb
Memory (After) : [304.972] Mb
Took 1.5 Seconds

the generator method

Memory (Before): [18.289] MB
Memory (After) : [18.300] MB
Took 1.578 Seconds

the list comprehension method

Memory (Before): [18.289] MB
Memory (After) : [18.914] MB
Took 1.71875 Seconds

כל פעם תפעילו מתודה אחת ותעשו comment לשניים האחרים.

את memory_profiler תצטרכו להתקין

import memory_profiler
import random
import time

names = ['John', 'Corey', 'Adam', 'Steve', 'Rick', 'Thomas']
majors = ['Math', 'Engineering', 'CompSci', 'Arts', 'Business']

print('Memory (Before): ' + str(memory_profiler.memory_usage()) + ' MB' )

def people_list(num_people):
    result = []
    for i in range(num_people):
        person = {
                    'id': i,
                    'name': random.choice(names),
                    'major': random.choice(majors)
                }
        result.append(person)
    return result

def people_generator(upper_bound):
    i = 0
    while i < upper_bound:
        person = {
                    'id': i,
                    'name': random.choice(names),
                    'major': random.choice(majors)
                }
        i += 1
        yield person

t1 = time.process_time()

population = 1000000

# the original method  

people = people_list(population)

# the generator method    <   -------------------------

#people_interator = people_generator(population)
#for _ in range(population):
#    next(people_interator)

# the list comprehension method    <   -------------------------

# people_interator = people_generator(population)
# list(people_interator)

t2 = time.process_time()
print('Memory (After) : {} Mb'.format(memory_profiler.memory_usage()))
print( 'Took {} Seconds'.format(t2-t1))

א. כמה תווים כבר יכולים להיות? 26 בשפה האנגלית. או שתרצה לספור גם את תוי הפיסוק/ רווח וכו’?
ב. אתה למעשה רוצה לוודא שה-KEY כבר קיים.
אז “אם התו קיים ב-KEYS” - תוסיף 1 לערך שלו. ואם טרם קיים - תציב 1 בערך שלו.
כדי לחסוך “אם” הייתי משתמש ב- defaultdict ו/או/ מקים מילון רגיל עם כל הערכים שאני מצפה עם VALUE = 0 ואז כל תו שאני פוגש - מגדיל את הכמות שלו ב-1

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

2 לייקים