GPars – מערכים מקביליים

הדוגמאות הראשונות שנראה בנושא של GPars הם די פשוטות וישירות ועוסקות בטיפול מקבילי באלמנטים של רשימה.

נתחיל בדוגמא הכי פשוטה – מעבר על הרשימה והדפסת כל האיברים

import groovyx.gpars.ParallelEnhancer

def list = 1..10000

//sequential

list.each { println it + ',' + Thread.currentThread()}

//concurrent

ParallelEnhancer.enhanceInstance(list)

list.asConcurrent {

                start = System.currentTimeMillis()

    list.each {println it + ',' + Thread.currentThread()}

}

בקוד רואים מעבר על הרשימה בצורה רגילה (סדרתית) ולאחר מכן את התחביר שנותן מעבר מקבילי – כל הדפסה של מספר מתבצעת מתוך Thread אחר.

דוגמא נוספת

import static groovyx.gpars.GParsPool.withPool

long start = System.currentTimeMillis()

def list1 = [1000,1000,1000,1000,1000,1000,1000,1000,1000,1000]

list1.each{ sleep it}

long con = System.currentTimeMillis()

withPool(10){

                list1.eachParallel{ sleep it.toLong()}

}

println "sequential: ${con-start}, concurrent: ${System.currentTimeMillis()-con}"

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

למה זה טוב?

יש שני תסריטים שבהם היכולת הזו היא מאוד שימושית.

הראשון הוא כאשר הקוד חסום בגלל משהו שאינו המעבד – למשל גישה לרשת. הרצת כמה פעולות כאלה במקביל חוסכת 'הצטברות' של הזמן בו ממתינים לתגובה משרתים אחרים ומאפשרת שיפור ביצועים אפילו על מעבד בודד. זה נקרא Fork/Join ונכנס גם לשפת ג'אווה עצמה. בגרובי כרגיל התחביר קצת יותר פשוט וידידותי. הדוגמא הבאה לקוחה מהתיעוד של GPars ומראה סריקה של מילים בכמה כתובות URL במקביל. אנשי ג'אווה מוזמנים לדמיין איך יראה אצלם קוד שעושה את זה:

def urls = ['http://www.dzone.com', 'http://www.theserverside.com', 'http://www.infoq.com']

withPool{

println 'Number of occurrences of the word GROOVY today: ' + urls.parallel

                .map {it.toURL().text.toUpperCase()}

                .filter {it.contains('GROOVY')}

                 .map{it.split()}

                 .map{it.findAll{word -> word.contains 'GROOVY'}.size()}

                .sum()

}

Map/reduce מכה שנית

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

def words = "This is just a plain text to count words in"

print count(words)

def count(arg) {

  withPool {

    return arg.parallel

 .map{[it, 1]}

.combine(0) {sum, value -> sum + value}.getParallel()

                .sort{-it.value}.collection

                }

}

(השורה המעניינת היא combine והיא מגדירה איך לבצע אגרגציה בין מפתחות שונים)

מטודות א-סינכרוניות

עוד יכולת נחמדה היא לקחת מטודות קיימות ולהפוך אותן בקלות לא-סינכרוניות. לאחר מכן ניתן לקרוא להן כרגיל אבל הן ירוצו ברקע. כמובן שניתן גם לחסום את המשך הריצה כדי להמתין שמטודה שרצה ברקע תסתיים (כמו Future). הנה דוגמא קטנה שעושה sleep sort:

// groovy sleep sort

def sleeper = {number -> sleep number*100; print "${number}, "}

withPool(10){

                def sorter = sleeper.asyncFun()

                [10,6,3,8,5,7,2,4,9].each{sorter it}

}

בפרק הבא…

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

כתיבת תגובה

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

הלוגו של WordPress.com

אתה מגיב באמצעות חשבון WordPress.com שלך. לצאת מהמערכת / לשנות )

תמונת Twitter

אתה מגיב באמצעות חשבון Twitter שלך. לצאת מהמערכת / לשנות )

תמונת Facebook

אתה מגיב באמצעות חשבון Facebook שלך. לצאת מהמערכת / לשנות )

תמונת גוגל פלוס

אתה מגיב באמצעות חשבון Google+ שלך. לצאת מהמערכת / לשנות )

מתחבר ל-%s