• בלוג
  • מיקבול תהליכים פשוט בפייתון

מיקבול תהליכים פשוט בפייתון

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

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

1. המשימה: חישוב MD5 של מחרוזות

משימה קלאסית למיקבול היא חישוב ערך MD5 של מחרוזות טקסט. הקוד הבא רץ על כל המחרוזות באורכים 1-6 ומחפש מילים שערך ה MD5 שלהן מופיע בקובץ מידע:

from __future__ import print_function
import string
import hashlib
import sys
import itertools

words = set(open('data.txt').read().split('\n'))

for r in range(1,7):
    print('Checking Size: {}'.format(r))
    for guess in (''.join(p) for p in itertools.product(string.lowercase, repeat=r)):
        md5 = hashlib.md5(guess).hexdigest()
        if md5 in words:
            print('Found: md5({guess}) = {md5}'.format(guess=guess, md5=md5))

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

2. מיקבול באמצעות Popen

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

from __future__ import print_function
import string
import hashlib
import sys
import itertools

words = set(open('data.txt').read().split('\n'))
first_letter = sys.argv[1]

for r in range(6):
    print('Checking Size: {}'.format(r + 1))
    for guess in (first_letter + ''.join(p) for p in itertools.product(string.lowercase, repeat=r)):
        md5 = hashlib.md5(guess).hexdigest()
        if md5 in words:
            print('Found: md5({guess}) = {md5}'.format(guess=guess, md5=md5))

עכשיו כל שנותר הוא להפעיל עותק של תוכנית כזו עבור כל אות, למשל דרך הסקריפט הבא:

from __future__ import print_function
import subprocess
import sys
import string

procs = [subprocess.Popen([sys.executable, 'calc_md5.py', l]) for l in string.lowercase]
for p in procs:
    p.wait()

print('--- done')

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