מבוא לשחקני Akka בג'אווה

1. הקדמה

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

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

2. מודל השחקן

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

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

שחקן מייצג יחידת חישוב עצמאית. כמה מאפיינים חשובים הם:

  • שחקן עוטף את מצבו ואת חלקו מהגיון היישום
  • שחקנים מתקשרים רק באמצעות הודעות אסינכרוניות ולעולם לא באמצעות שיחות ישירות בשיטה
  • לכל שחקן יש כתובת ייחודית ותיבת דואר שבה שחקנים אחרים יכולים להעביר הודעות
  • השחקן יעבד את כל ההודעות בתיבת הדואר בסדר רציף (יישום ברירת המחדל של תיבת הדואר הוא תור FIFO)
  • מערכת השחקנים מאורגנת בהיררכיה דמוית עץ
  • שחקן יכול ליצור שחקנים אחרים, יכול לשלוח הודעות לכל שחקן אחר ולעצור את עצמו או כל שחקן שנוצר

2.1. יתרונות

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

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

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

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

3. התקנה

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

 com.typesafe.akka akka-actor_2.12 2.5.11 

4. יצירת שחקן

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

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

מערכת ActorSystem = ActorSystem.create ("מערכת הבדיקה"); 

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

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

כל שחקן Akka יאריך את AbstractActor מחלקה מופשטת ויישום createReceive () שיטה לטיפול בהודעות הנכנסות משחקנים אחרים:

מחלקה ציבורית MyActor מרחיב את AbstractActor {public Receive createReceive () {return receiveBuilder (). build (); }}

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

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

ActorRef readingActorRef = system.actorOf (Props.create (MyActor.class), "השחקן שלי");

4.1. תצורת השחקן

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

מומלץ מאוד ונחשב לשיטה הטובה ביותר להגדיר את שיטות המפעל בתוך אובייקט השחקן שיטפל ביצירת ה- אביזרים לְהִתְנַגֵד.

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

כיתה ציבורית ReadingActor מרחיב את AbstractActor {טקסט מחרוזת פרטי; אביזרי אבזרי סטטי ציבוריים (טקסט מחרוזת) {החזר Props.create (ReadingActor.class, טקסט); } // ...}

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

ActorRef readingActorRef = system.actorOf (ReadingActor.props (TEXT), "readingActor");

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

5. מסרים של שחקן

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

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

5.1. שליחת הודעות

בתוך שחקן Akka שולחים הודעות מערכת בשיטות:

  • לאמר()
  • לִשְׁאוֹל()
  • קָדִימָה()

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

readingActorRef.tell (ReadingActor.ReadLines חדש (), ActorRef.noSender ()); 

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

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

בדרך כלל, אנו יכולים להגדיר את הפרמטר השני ל- ריק אוֹ ActorRef.noSender ()כי אנחנו לא מצפים לתשובה. כאשר אנו זקוקים לתגובה משחקן, אנו יכולים להשתמש ב- לִשְׁאוֹל() שיטה:

עתיד CompletableFuture = ask (wordCounterActorRef, WordCounterActor.CountWords חדש (שורה), 1000) .toCompletableFuture ();

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

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

זה לא נעשה באופן אוטומטי כאשר שחקן משליך חריג בזמן עיבוד ההודעה וה- לִשְׁאוֹל() פסק זמן לשיחה ולא יופיע ביומן כל התייחסות לחריג:

@Override ציבור קבל createReceive () {return receiveBuilder () .match (CountWords.class, r -> {try {int numberOfWords = countWordsFromLine (r.line); getSender (). Tell (numberOfWords, getSelf ());} לתפוס (יוצא מן הכלל לשעבר) {getSender (). ספר (akka.actor חדש.Status.Failure (ex), getSelf ()); לזרוק ex;}}). Build (); }

יש לנו גם את קָדִימָה() שיטה הדומה ל- לאמר(). ההבדל הוא ששולח ההודעה המקורי נשמר בעת שליחת ההודעה, כך שהשחקן המעביר את ההודעה פועל רק כשחקן מתווך:

printerActorRef.forward (PrinterActor.PrintFinalResult חדש (totalNumberOfWords), getContext ());

5.2. קבלת הודעות

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

public Receive createReceive () {return receipBuilder (). matchEquals ("printit", p -> {System.out.println ("הכתובת של שחקן זה היא:" + getSelf ());}). build (); }

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

6. הריגת שחקן

כשסיימנו להשתמש בשחקן אנחנו יכולים לעצור את זה על ידי קריאה ל תפסיק() שיטה מ ה ActorRefFactory מִמְשָׁק:

system.stop (myActorRef);

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

על ידי עצירת שחקן הורים, אנו גם נשלח אות הרג לכל השחקנים הילדים שהולידו אותו.

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

העתיד terminateResponse = system.terminate ();

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

נוכל לשלוח גם גלולת רעל הוֹדָעָה לכל שחקן שאנחנו רוצים להרוג:

myActorRef.tell (PoisonPill.getInstance (), ActorRef.noSender ());

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

מסר מיוחד נוסף המשמש להרוג שחקן הוא לַהֲרוֹג הוֹדָעָה. לא כמו ה גלולת רעל, השחקן יזרוק ActorKilledException בעת עיבוד הודעה זו:

myActorRef.tell (Kill.getInstance (), ActorRef.noSender ());

7. מסקנה

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

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

  • להשתמש לאמר() במקום לִשְׁאוֹל() כאשר ביצועים הם עניין
  • כשמשתמש לִשְׁאוֹל() עלינו תמיד לטפל בחריגים על ידי שליחת a כישלון הוֹדָעָה
  • שחקנים לא צריכים לשתף שום מדינה משתנה
  • אין להכריז על שחקן בתוך שחקן אחר
  • השחקנים לא נעצרים אוטומטית כאשר כבר לא מפנים אותם. עלינו להשמיד במפורש שחקן כאשר איננו זקוקים לו יותר בכדי למנוע דליפות זיכרון
  • הודעות המשמשות שחקנים תמיד צריך להיות משתנה

כמו תמיד, קוד המקור של המאמר זמין באתר GitHub.


$config[zx-auto] not found$config[zx-overlay] not found