מבוא למזיין גויאבה

1. סקירה כללית

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

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

1.1. שינון לעומת מטמון

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

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

1.2. מזכר גויאבה ומטמון גויאבה

גויאבה תומכת הן בשינוי שיניים והן במטמון. שינון זכויות חל על פונקציות ללא ויכוח (ספק) ומתפקד בדיוק עם טיעון אחד (פוּנקצִיָה). ספק ו פוּנקצִיָה כאן עיין בממשקים פונקציונליים של גויאבה שהם מחלקות משנה ישירות של ממשקי API פונקציונליים של Java 8 עם אותם שמות.

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

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

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

2. ספק שינון

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

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

בואו נחקור כל שיטה של ספקתזכורת.

2.1. ספק שינון ללא פינוי

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

ספק memoizedSupplier = Suppliers.memoize (CostlySupplier :: createBigNumber);

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

2.2. ספק שינון עם פינוי על ידי זמן לחיות (TTL)

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

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

ספק memoizedSupplier = Suppliers.memoizeWithExpiration (CostlySupplier :: createBigNumber, 5, TimeUnit.SECONDS);

לאחר שחלף הזמן שצוין (5 שניות), המטמון יפנה את הערך המוחזר של ה- ספק מהזיכרון וכל שיחה שלאחר מכן אל לקבל השיטה תבוצע מחדש createBigNumber.

למידע מפורט יותר, עיין ב- Javadoc.

2.3. דוגמא

בואו לדמות שיטה יקרה חישובית בשם createBigNumber:

מחלקה ציבורית CostlySupplier {BigInteger פרטי סטטי GenerateBigNumber () {נסה {TimeUnit.SECONDS.sleep (2); } לתפוס (InterruptedException e) {} להחזיר BigInteger חדש ("12345"); }}

לשיטת הדוגמה שלנו ייקח 2 שניות לביצוע ואז תחזיר a ביג-שלם תוֹצָאָה. נוכל להזכיר אותו באמצעות תזכיר אוֹ memoizeWithExpiration ממשקי API.

לשם פשטות נשמיט את מדיניות הפינוי:

@Test הציבור בטל givenMemoizedSupplier_whenGet_thenSubsequentGetsAreFast () {ספק memoizedSupplier; memoizedSupplier = Suppliers.memoize (CostlySupplier :: createBigNumber); BigInteger expectValue = BigInteger חדש ("12345"); assertSupplierGetExecutionResultAndDuration (memoizedSupplier, expectedValue, 2000D); assertSupplierGetExecutionResultAndDuration (memoizedSupplier, expectedValue, 0D); assertSupplierGetExecutionResultAndDuration (memoizedSupplier, expectedValue, 0D); } בטל פרטי assertSupplierGetExecutionResultAndDuration (ספק הספק, T expectValue, כפול expectDurationInMs) {התחלה מיידית = Instant.now (); ערך T = ספק. Get (); DurationInMs = Duration.between (התחלה, Instant.now ()). ToMillis (); marginOfErrorInMs כפול = 100D; assertThat (value, is (equalTo (expectedValue))); assertThat (durationInMs.doubleValue (), הוא (closeTo (expectDurationInMs, marginOfErrorInMs))); }

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

3. פוּנקצִיָה שינון

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

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

טעינת מטמוןהמפתח הוא פוּנקצִיָההוויכוח / קלט, בעוד שערך המפה הוא פוּנקצִיָההערך המוחזר:

תזכיר LoadingCache = CacheBuilder.newBuilder () .build (CacheLoader.from (FibonacciSequence :: getFibonacciNumber));

מאז טעינת מטמון היא מפה בו זמנית, זה לא מאפשר מפתחות או ערכי null. לכן עלינו להבטיח שה- פוּנקצִיָה אינו תומך ב- null כוויכוח או מחזיר ערכי null.

3.1. פוּנקצִיָה שינון עם מדיניות פינוי

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

למשל, אנו יכולים לפנות את הערכים שהיו בטלים במשך 2 שניות:

תזכיר LoadingCache = CacheBuilder.newBuilder () .expireAfterAccess (2, TimeUnit.SECONDS) .build (CacheLoader.from (פיבונאצ'י :: getFibonacciNumber));

לאחר מכן, בואו נסתכל על שני מקרי שימוש של פוּנקצִיָה תזכורת: רצף פיבונאצ'י ופקטוריאלי.

3.2. דוגמה לרצף פיבונאצ'י

אנו יכולים לחשב רקורסיבית מספר פיבונאצ'י ממספר נתון נ:

BigInteger סטטי ציבורי getFibonacciNumber (int n) {if (n == 0) {להחזיר BigInteger.ZERO; } אחר אם (n == 1) {להחזיר BigInteger.ONE; } אחר {להחזיר getFibonacciNumber (n - 1). להוסיף (getFibonacciNumber (n - 2)); }}

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

כדי לשפר את היעילות והביצועים, נוכל להזכיר שירים getFibonacciNumber באמצעות מטמון מטמון ו CacheBuilder, ציון מדיניות הפינוי במידת הצורך.

בדוגמה הבאה, אנו מסירים את הערך הישן ביותר ברגע שגודל התזכורת הגיע ל 100 ערכים:

מחלקה ציבורית FibonacciSequence {תזכיר LoadingCache סטטי פרטי = CacheBuilder.newBuilder () .maximumSize (100) .build (CacheLoader.from (FibonacciSequence :: getFibonacciNumber)); BigInteger סטטי ציבורי getFibonacciNumber (int n) {if (n == 0) {להחזיר BigInteger.ZERO; } אחר אם (n == 1) {להחזיר BigInteger.ONE; } אחר {להחזיר תזכיר. getUnchecked (n - 1). להוסיף (memo.getUnchecked (n - 2)); }}}

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

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

למידע מפורט יותר, עיין ב- Javadoc.

3.3. דוגמה עובדתית

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

BigInteger סטטי ציבורי getFactorial (int n) {if (n == 0) {return BigInteger.ONE; } אחר {החזר BigInteger.valueOf (n). מרובה (getFactorial (n - 1)); }}

אנו יכולים לשפר את היעילות של יישום זה על ידי יישום תזכורת:

מחלקה ציבורית פקטוריאל {תזכורת סטטית פרטית של LoadingCache = CacheBuilder.newBuilder () .build (CacheLoader.from (Factorial :: getFactorial)); BigInteger סטטי ציבורי getFactorial (int n) {if (n == 0) {return BigInteger.ONE; } אחר {להחזיר BigInteger.valueOf (n). מרובה (תזכיר. getUnchecked (n - 1)); }}}

4. מסקנה

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

כמו תמיד, ניתן למצוא את קוד המקור ב- GitHub.


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