Skyframe StateMachines का इस्तेमाल करने के लिए गाइड

किसी समस्या की शिकायत करें सोर्स देखें रात · 7.3 · 7.2 · 7.1 · 7.0 · 6.5

खास जानकारी

Skyframe StateMachine एक डिकोड किया गया फ़ंक्शन-ऑब्जेक्ट है, जो हीप. यह सुविधा, किसी भी काम के लिए बार-बार उपलब्ध होने और आकलन करने में मदद करती है.1 ऐसा तब होता है, जब ज़रूरी वैल्यू तुरंत उपलब्ध नहीं होती हैं. हालांकि, इनका आकलन एसिंक्रोनस तरीके से किया जाता है. कॉन्टेंट बनाने इंतज़ार करते समय, StateMachine किसी थ्रेड रिसॉर्स को टाई अप नहीं कर सकता, बल्कि उसे यह करना होगा निलंबित और फिर से शुरू किया जाएगा. इस तरह, डिकंस्ट्रक्शन से उपयोगकर्ता को वापस आने का साफ़ तौर पर पता चलता है अंक ताकि पिछले कंप्यूटेशन को स्किप किया जा सके.

StateMachine का इस्तेमाल क्रम, ब्रांचिंग, स्ट्रक्चर्ड लॉजिकल को बताने के लिए किया जा सकता है साथ ही, इन्हें खास तौर पर Skyframe इंटरैक्शन के लिए तैयार किया गया है. StateMachine को ज़्यादा बड़े StateMachine में बनाया जा सकता है और शेयर किया जा सकता है सब-StateMachine. कॉन करंसी हमेशा हैरारकी के हिसाब से होती है, पूरी तरह तार्किक है. सभी समवर्ती सबटास्क एक ही शेयर किए गए पैरंट में चलते हैं SkyFunction थ्रेड.

परिचय

इस सेक्शन में, StateMachine के बारे में जानकारी दी गई है. java.com.google.devtools.build.skyframe.state पैकेज.

Skyframe के रीस्टार्ट होने के बारे में जानकारी

Skyframe एक फ़्रेमवर्क है, जो डिपेंडेंसी ग्राफ़ की पैरलल इवैलुएशन करता है. ग्राफ़ का हर नोड, SkyKey अपने पैरामीटर और SkyValue के नतीजे को बताता है. कॉन्टेंट बनाने कंप्यूटेशनल मॉडल इस तरह का है कि SkyFunction, SkyKey से SkyValues का पता लगा पाता है. अतिरिक्त SkyFunctions का बार-बार और साथ-साथ आकलन करने की सुविधा देता है. इसके बजाय ब्लॉक की जा रही है, जिससे अनुरोध किया गया SkyValue नहीं होने पर, थ्रेड बाँधता है तैयार है क्योंकि कंप्यूटेशन के कुछ सबग्राफ़ अधूरे हैं, इसलिए SkyFunction को null getValue रिस्पॉन्स मिलता है और यह null रिस्पॉन्स देता है SkyValue के बजाय, यह बताता है कि इनपुट मौजूद न होने की वजह से यह अधूरा है. पहले सभी SkyValues का अनुरोध किए जाने पर SkyFrame, SkyFunctions को फिर से शुरू करता है उपलब्ध होने चाहिए.

SkyKeyComputeState के आने से पहले, हैंडलिंग का पारंपरिक तरीका तो रीस्टार्ट हुआ, लेकिन कंप्यूटेशन को पूरी तरह से दोबारा चलाने के लिए. हालांकि यह द्विघाती है इसलिए, इस तरीके से लिखे गए फ़ंक्शन लंबे समय तक काम करते हैं, क्योंकि हर बार फिर से चलाया जाता है. कम लुकअप से null दिखेगा. SkyKeyComputeState से ये काम किए जा सकते हैं मैन्युअल तरीके से तय किए गए चेक-पॉइंट डेटा को SkyFunction के साथ जोड़ें. इससे कंप्यूटेशन.

StateMachine ऐसे ऑब्जेक्ट होते हैं जो SkyKeyComputeState के अंदर रहते हैं और उन्हें हटा देते हैं SkyFunction के रीस्टार्ट होने पर असल में सभी रीकंप्यूटेशन (आकलन के हिसाब से) SkyKeyComputeState कैश मेमोरी में सेव नहीं होता) हुक को प्रोसेस करना.

SkyKeyComputeState में स्टेटफ़ुल कंप्यूटेशन

ऑब्जेक्ट को ध्यान में रखकर डिज़ाइन किए गए प्रॉडक्ट के हिसाब से, उसे स्टोर करने पूरी डेटा वैल्यू के बजाय, SkyKeyComputeState में कंप्यूटेशनल ऑब्जेक्ट. Java में, ऑब्जेक्ट को ले जाने वाले व्यवहार का कम से कम विवरण काम करने में मदद करता है और यह काफ़ी कारगर साबित होता है. StateMachine के पास नीचे दिया गया है, जो बार-बार दिखता है और परिभाषा2.

@FunctionalInterface
public interface StateMachine {
  StateMachine step(Tasks tasks) throws InterruptedException;
}

Tasks इंटरफ़ेस, SkyFunction.Environment के जैसा है, लेकिन यह इसे एसिंक्रोनस के लिए डिज़ाइन किया गया है. साथ ही, यह लॉजिक के साथ एक साथ किए जाने वाले सबटास्क के लिए भी सहायता उपलब्ध कराता है3.

step की रिटर्न वैल्यू एक और StateMachine है, जो स्पेसिफ़िकेशन को अनुमति देती है चरणों के क्रम को शामिल किया जा सकता है. step, DONE फ़ंक्शन को नतीजे के तौर पर तब दिखाता है, जब StateMachine हो गया है. उदाहरण के लिए:

class HelloWorld implements StateMachine {
  @Override
  public StateMachine step(Tasks tasks) {
    System.out.println("hello");
    return this::step2;  // The next step is HelloWorld.step2.
  }

  private StateMachine step2(Tasks tasks) {
     System.out.println("world");
     // DONE is special value defined in the `StateMachine` interface signaling
     // that the computation is done.
     return DONE;
  }
}

नीचे दिए गए आउटपुट के साथ StateMachine का ब्यौरा देता है.

hello
world

ध्यान दें कि मेथड रेफ़रंस this::step2, StateMachine भी है. इसकी वजह यह है step2, StateMachine के फ़ंक्शनल इंटरफ़ेस की परिभाषा के हिसाब से काम करता है. तरीका में अगली स्थिति तय करने का सबसे सामान्य तरीका रेफ़रंस है, StateMachine.

निलंबित और फिर से शुरू करना

आसानी से, कंप्यूटेशन को StateMachine चरणों में बांटकर, मोनोलिथिक फ़ंक्शन, यूआरएल को निलंबित और फिर से शुरू करने के लिए ज़रूरी हुक देता है कंप्यूटेशन. जब StateMachine.step वापस लौटता है, तो साफ़ तौर पर निलंबन लगता है अंक. वापस दिए गए StateMachine मान से तय किया गया क्रम साफ़ तौर पर रिज़्यूमे पॉइंट. इसलिए, रीकंप्यूटेशन (फिर से गिनती) से बचा जा सकता है, क्योंकि कंप्यूटेशन को ठीक वहीं से शुरू किया जा सकता है जहां उन्हें छोड़ा गया था.

कॉलबैक, कंटिन्युएशन, और एसिंक्रोनस कंप्यूटेशन

तकनीकी शब्दों में, StateMachine एक निरंतर के रूप में काम करता है, जिससे तय होता है कि की जांच की जाएगी. ब्लॉक करने के बजाय, StateMachine ये काम कर सकता है step फ़ंक्शन से वापस आने पर, अपने मन से निलंबित करें, जिससे किसी Driver इंस्टेंस पर वापस नियंत्रित करें. Driver यह कर सकता है इसके बाद, तैयार StateMachine पर स्विच करें या कंट्रोल को फिर से Skyframe पर छोड़ दें.

परंपरागत रूप से, कॉलबैक और कंटिन्युएशन को एक ही सिद्धांत में रखा गया है. हालांकि, StateMachine इन दोनों के बीच अंतर बनाए रखता है.

  • कॉलबैक - इससे पता चलता है कि एसिंक्रोनस के नतीजे को कहां सेव करना है कंप्यूटेशन.
  • कंटिन्युएशन - एक्ज़ीक्यूशन की अगली स्थिति के बारे में बताता है.

किसी एसिंक्रोनस कार्रवाई शुरू करते समय कॉलबैक की ज़रूरत होती है, जिसका मतलब है कि मेथड को कॉल करने के तुरंत बाद वास्तविक कार्रवाई नहीं होती, का उदाहरण देखें. कॉलबैक को जितना हो सके उतना आसान रखें.

कंटिन्युएशंस, StateMachine की StateMachines और सभी एसिंक्रोनस के बाद होने वाले कॉम्प्लेक्स एक्ज़ीक्यूशन को इनकैप्सुलेट करें कंप्यूटेशन रिज़ॉल्व. इस स्ट्रक्चर्ड तरीके की मदद से, कॉलबैक मैनेज किए जा सकते हैं.

Tasks

Tasks इंटरफ़ेस में, SkyValues को देखने के लिए, StateMachine को एपीआई के साथ दिया जाता है साथ ही, एक साथ कई सबटास्क शेड्यूल किए जा सकते हैं.

interface Tasks {
  void enqueue(StateMachine subtask);

  void lookUp(SkyKey key, Consumer<SkyValue> sink);

  <E extends Exception>
  void lookUp(SkyKey key, Class<E> exceptionClass, ValueOrExceptionSink<E> sink);

  // lookUp overloads for 2 and 3 exception types exist, but are elided here.
}

SkyValue लुकअप

StateMachines, SkyValues देखने के लिए Tasks.lookUp ओवरलोड का इस्तेमाल करते हैं. वे हैं SkyFunction.Environment.getValue और SkyFunction.Environment.getValueOrThrow और अपवाद मैनेज करने के ये तरीके एक जैसे हैं सिमेंटिक्स. लागू करने पर, तुरंत लुकअप नहीं होता, लेकिन इसके बजाय, ऐसा करने से पहले ज़्यादा से ज़्यादा लुकअप 4 को एक साथ बनाता है. वैल्यू हो सकता है कि तुरंत उपलब्ध न हो. उदाहरण के लिए, Skyframe को रीस्टार्ट करने के बाद, इसलिए कॉलर यह बताता है कि कॉलबैक का इस्तेमाल करके, नतीजे में मिली वैल्यू का क्या करना है.

StateMachine प्रोसेसर (Driver और से कनेक्ट कर रहा है SkyFrame) यह गारंटी देता है कि वैल्यू अगली स्थिति शुरू होती है. इसका एक उदाहरण यहां दिया गया है.

class DoesLookup implements StateMachine, Consumer<SkyValue> {
  private Value value;

  @Override
  public StateMachine step(Tasks tasks) {
    tasks.lookUp(new Key(), (Consumer<SkyValue>) this);
    return this::processValue;
  }

  // The `lookUp` call in `step` causes this to be called before `processValue`.
  @Override  // Implementation of Consumer<SkyValue>.
  public void accept(SkyValue value) {
    this.value = (Value)value;
  }

  private StateMachine processValue(Tasks tasks) {
    System.out.println(value);  // Prints the string representation of `value`.
    return DONE;
  }
}

ऊपर दिए गए उदाहरण में, पहला चरण पासिंग new Key() को दिखाता है उपभोक्ता के तौर पर this. ऐसा इसलिए हो सकता है, क्योंकि DoesLookup लागू करता है Consumer<SkyValue>.

समझौते के हिसाब से, अगली स्थिति DoesLookup.processValue शुरू होने से पहले, सभी DoesLookup.step के लुकअप पूरे हो गए. इसलिए, value का इस्तेमाल तब किया जा सकता है, जब इसे processValue में ऐक्सेस किया जाता है.

सबटास्क

Tasks.enqueue, तर्क के साथ एक साथ किए जाने वाले सबटास्क चलाने का अनुरोध करता है. सबटास्क StateMachines भी हो सकते हैं और नियमित तौर पर कुछ भी StateMachine किया जा सकता है इनमें बार-बार सबटास्क बनाना या SkyValues देखना शामिल है. lookUp की तरह ही, स्टेट मशीन ड्राइवर पक्का करता है कि सभी सबटास्क पूरा करें. इसका एक उदाहरण यहां दिया गया है.

class Subtasks implements StateMachine {
  private int i = 0;

  @Override
  public StateMachine step(Tasks tasks) {
    tasks.enqueue(new Subtask1());
    tasks.enqueue(new Subtask2());
    // The next step is Subtasks.processResults. It won't be called until both
    // Subtask1 and Subtask 2 are complete.
    return this::processResults;
  }

  private StateMachine processResults(Tasks tasks) {
    System.out.println(i);  // Prints "3".
    return DONE;  // Subtasks is done.
  }

  private class Subtask1 implements StateMachine {
    @Override
    public StateMachine step(Tasks tasks) {
      i += 1;
      return DONE;  // Subtask1 is done.
    }
  }

  private class Subtask2 implements StateMachine {
    @Override
    public StateMachine step(Tasks tasks) {
      i += 2;
      return DONE;  // Subtask2 is done.
    }
  }
}

हालांकि Subtask1 और Subtask2 लॉजिकल रूप से एक साथ हैं, लेकिन सभी कुछ एक ही थ्रेड को व्यवस्थित करें, ताकि "एक साथ कई" i के अपडेट के लिए कोई ज़रूरत नहीं है सिंक करना.

स्ट्रक्चर्ड कॉनकरंसी

क्योंकि हर lookUp और enqueue को अगले चरण पर जाने से पहले समाधान होना ज़रूरी है नहीं है, तो इसका मतलब है कि एक ही समय पर कई सुविधाओं वाला एक ही कोड, नैचुरल तरीके से ट्री स्ट्रक्चर तक सीमित है. यह समय है क्रम के हिसाब से5 एक साथ कई काम किए जा सकते हैं, जैसा कि यहां दिखाया गया है उदाहरण के लिए.

स्ट्रक्चर्ड कॉनकरेंसी

UML से यह कहना मुश्किल है कि एक साथ कई काम करने वाले स्ट्रक्चर से एक पेड़ बनता है. इसमें वैकल्पिक व्यू मौजूद है, जो ट्री स्ट्रक्चर.

अनस्ट्रक्चर्ड कॉनकरेंसी

एक साथ कई काम करने के आंकड़ों की वजह समझना आसान है.

कंपोज़िशन और कंट्रोल फ़्लो पैटर्न

इस सेक्शन में उदाहरण दिए गए हैं कि एक से ज़्यादा StateMachine कैसे बनाए जा सकते हैं और कुछ कंट्रोल फ़्लो से जुड़ी समस्याओं के समाधान मिलते हैं.

क्रम के बाद वाली स्थितियां

यह सबसे सामान्य और सीधा कंट्रोल फ़्लो पैटर्न है. इसका एक उदाहरण इसे स्टेटफ़ुल कंप्यूटेशन SkyKeyComputeState.

ब्रांचिंग

StateMachine सेकंड में ब्रांचिंग स्टेटस हासिल करने के लिए, अलग-अलग सामान्य Java कंट्रोल फ़्लो का इस्तेमाल करने वाली वैल्यू, जैसा कि नीचे दिए गए उदाहरण में दिखाया गया है.

class Branch implements StateMachine {
  @Override
  public StateMachine step(Tasks tasks) {
    // Returns different state machines, depending on condition.
    if (shouldUseA()) {
      return this::performA;
    }
    return this::performB;
  }
  …
}

कुछ शाखाओं के लिए, जल्दी पूरा होने के लिए DONE लौटाना आम बात है.

बेहतर क्रम में कंपोज़िशन

StateMachine के कंट्रोल के लिए मेमोरी नहीं है, इसलिए StateMachine को शेयर किया जा रहा है सबटास्क के तौर पर कई बार परिभाषाएं समझना मुश्किल हो सकता है. M1 और M2, StateMachine, S को शेयर करने वाले StateMachine इंस्टेंस होते हैं, M1 और M2 का क्रम <A, S, B> है और <X, S, Y>. समस्या यह है कि S को यह नहीं पता कि पूरा होने के बाद B या Y पर जारी रखें और StateMachine कॉल स्टैक. इस सेक्शन में, इस लक्ष्य को हासिल करने की कुछ तकनीकों के बारे में बताया गया है.

टर्मिनल क्रम एलिमेंट के तौर पर StateMachine

इससे शुरुआती समस्या हल नहीं होती. यह सिर्फ़ क्रम में चलने वाले नतीजे दिखाता है कंपोज़िशन जब शेयर किया गया StateMachine क्रम में टर्मिनल होता है.

// S is the shared state machine.
class S implements StateMachine { … }

class M1 implements StateMachine {
  @Override
  public StateMachine step(Tasks tasks) {
    performA();
    return new S();
  }
}

class M2 implements StateMachine {
  @Override
  public StateMachine step(Tasks tasks) {
    performX();
    return new S();
  }
}

यह तब भी काम करता है, जब S खुद एक कॉम्प्लेक्स स्टेट मशीन है.

क्रम में चलने वाली कंपोज़िशन के लिए सबटास्क

सूची में जोड़े गए सबटास्क को अगली स्थिति से पहले पूरा होने की गारंटी है. इसलिए, यह कभी-कभी सबटास्क के तरीके6 का थोड़ा-बहुत गलत इस्तेमाल किया जा सकता है.

class M1 implements StateMachine {
  @Override
  public StateMachine step(Tasks tasks) {
    performA();
    // S starts after `step` returns and by contract must complete before `doB`
    // begins. It is effectively sequential, inducing the sequence < A, S, B >.
    tasks.enqueue(new S());
    return this::doB;
  }

  private StateMachine doB(Tasks tasks) {
    performB();
    return DONE;
  }
}

class M2 implements StateMachine {
  @Override
  public StateMachine step(Tasks tasks) {
    performX();
    // Similarly, this induces the sequence < X, S, Y>.
    tasks.enqueue(new S());
    return this::doY;
  }

  private StateMachine doY(Tasks tasks) {
    performY();
    return DONE;
  }
}

runAfter इंजेक्शन

कभी-कभी, Tasks.enqueue का गलत इस्तेमाल करना मुमकिन नहीं होता, क्योंकि अन्य साथ-साथ चलने वाले सबटास्क या Tasks.lookUp कॉल, जिन्हें S से पहले पूरा करना ज़रूरी है लागू करता है. इस मामले में, runAfter पैरामीटर को S में इंजेक्ट करने से, इन कामों के लिए इस्तेमाल किया जा सकता है S को बताएं कि आगे क्या करना है.

class S implements StateMachine {
  // Specifies what to run after S completes.
  private final StateMachine runAfter;

  @Override
  public StateMachine step(Tasks tasks) {
    … // Performs some computations.
    return this::processResults;
  }

  @Nullable
  private StateMachine processResults(Tasks tasks) {
    … // Does some additional processing.

    // Executes the state machine defined by `runAfter` after S completes.
    return runAfter;
  }
}

class M1 implements StateMachine {
  @Override
  public StateMachine step(Tasks tasks) {
    performA();
    // Passes `this::doB` as the `runAfter` parameter of S, resulting in the
    // sequence < A, S, B >.
    return new S(/* runAfter= */ this::doB);
  }

  private StateMachine doB(Tasks tasks) {
    performB();
    return DONE;
  }
}

class M2 implements StateMachine {
  @Override
  public StateMachine step(Tasks tasks) {
    performX();
    // Passes `this::doY` as the `runAfter` parameter of S, resulting in the
    // sequence < X, S, Y >.
    return new S(/* runAfter= */ this::doY);
  }

  private StateMachine doY(Tasks tasks) {
    performY();
    return DONE;
  }
}

यह तरीका, सबटास्क का गलत इस्तेमाल करने से बेहतर है. हालांकि, इसे लागू करने से भी उदाहरण के लिए, runAfter की मदद से कई StateMachine को नेस्ट करने पर, कॉलबैक हेल का रास्ता. क्रम में चलने वाले सेगमेंट को अलग-अलग करना बेहतर है इसके बजाय, सामान्य क्रम में चलने वाले runAfter.

  return new S(/* runAfter= */ new T(/* runAfter= */ this::nextStep))

को निम्न से बदला जा सकता है.

  private StateMachine step1(Tasks tasks) {
     doStep1();
     return new S(/* runAfter= */ this::intermediateStep);
  }

  private StateMachine intermediateStep(Tasks tasks) {
    return new T(/* runAfter= */ this::nextStep);
  }

अनुमति नहीं है विकल्प: runAfterUnlessError

इससे पहले के ड्राफ़्ट में, हमने रद्द करने के लिए runAfterUnlessError पर विचार किया था गड़बड़ियों को ठीक करने में मदद मिलती है. यह इस तथ्य की ओर इशारा करता था कि अक्सर गलतियां हो जाती हैं दो बार जाँचा जाता है, एक बार StateMachine से, जिसमें एक runAfter संदर्भ होता है और एक बार runAfter मशीन से.

कुछ सोच-विचार करने के बाद, हमने तय किया कि कोड की एकरूपता यह गड़बड़ी की जाँच करने की कॉपी करने से ज़्यादा ज़रूरी है. यह भ्रामक होगा अगर runAfter सिस्टम ने tasks.enqueue तकनीक है, जिसके लिए हमेशा गड़बड़ी की जांच करना ज़रूरी होता है.

सीधे तौर पर ऐक्सेस देना

हर बार फ़ॉर्मल स्टेट ट्रांज़िशन होने पर, मुख्य Driver लूप आगे बढ़ जाता है. समझौते के हिसाब से, स्थितियों को बेहतर बनाने का मतलब है कि वे सभी लोग SkyValue में शामिल हैं जिन्हें पहले जोड़ा जा चुका है लुकअप और सबटास्क, अगली स्थिति के लागू होने से पहले ही ठीक हो जाते हैं. कभी-कभी यह तर्क डेलिगेट के लिए StateMachine का इस्तेमाल करने पर, फ़ेज़ को ऐडवांस बनाने की ज़रूरत नहीं होती या गलत असर. उदाहरण के लिए, अगर प्रतिनिधि का पहला step काम करता है SkyKey तो ऐसे लुकअप जिन्हें सौंपी गई स्थिति के लुकअप के साथ साथ चलाया जा सकता है तो आगे के चरण उन्हें क्रम के मुताबिक बना देंगे. इसका मतलब यह हो सकता है कि नीचे दिए गए उदाहरण की मदद से, सीधे डेटा का ऐक्सेस दें.

class Parent implements StateMachine {
  @Override
  public StateMachine step(Tasks tasks ) {
    tasks.lookUp(new Key1(), this);
    // Directly delegates to `Delegate`.
    //
    // The (valid) alternative:
    //   return new Delegate(this::afterDelegation);
    // would cause `Delegate.step` to execute after `step` completes which would
    // cause lookups of `Key1` and `Key2` to be sequential instead of parallel.
    return new Delegate(this::afterDelegation).step(tasks);
  }

  private StateMachine afterDelegation(Tasks tasks) {
    …
  }
}

class Delegate implements StateMachine {
  private final StateMachine runAfter;

  Delegate(StateMachine runAfter) {
    this.runAfter = runAfter;
  }

  @Override
  public StateMachine step(Tasks tasks) {
    tasks.lookUp(new Key2(), this);
    return …;
  }

  // Rest of implementation.
  …

  private StateMachine complete(Tasks tasks) {
    …
    return runAfter;
  }
}

डेटा फ़्लो

पिछली बातचीत का मुख्य मकसद, कंट्रोल फ़्लो को मैनेज करना था. यह सेक्शन में, डेटा वैल्यू के प्रोपेशन के बारे में बताया गया है.

Tasks.lookUp कॉलबैक लागू किया जा रहा है

SkyValue में, Tasks.lookUp कॉलबैक लागू करने का एक उदाहरण दिया गया है देखें. इस सेक्शन में वजह और सुझाव दिए गए हैं कई SkyValues को हैंडल करने के तरीके अपनाता है.

Tasks.lookUp कॉलबैक

Tasks.lookUp वाला तरीका, पैरामीटर के तौर पर कॉलबैक, sink को लेता है.

  void lookUp(SkyKey key, Consumer<SkyValue> sink);

इसे लागू करने के लिए, मुहावरे वाला तरीका Java लैम्डा का इस्तेमाल करना होगा:

  tasks.lookUp(key, value -> myValue = (MyValueClass)value);

जहां myValue, StateMachine इंस्टेंस का सदस्य वैरिएबल है खोजें. हालांकि, Lambda फ़ंक्शन को StateMachine में Consumer<SkyValue> इंटरफ़ेस लागू करना लागू करना. Lambda फ़ंक्शन तब भी काम आता है, जब इस तरह के कई लुकअप हों और सवाल कुछ आसान नहीं होगा.

Tasks.lookUp के ओवरलोड को मैनेज करने में भी गड़बड़ियां हैं. ये गड़बड़ियां ठीक वैसी ही होती हैं जैसी हैं SkyFunction.Environment.getValueOrThrow.

  <E extends Exception> void lookUp(
      SkyKey key, Class<E> exceptionClass, ValueOrExceptionSink<E> sink);

  interface ValueOrExceptionSink<E extends Exception> {
    void acceptValueOrException(@Nullable SkyValue value, @Nullable E exception);
  }

इसे लागू करने का एक उदाहरण नीचे दिया गया है.

class PerformLookupWithError extends StateMachine, ValueOrExceptionSink<MyException> {
  private MyValue value;
  private MyException error;

  @Override
  public StateMachine step(Tasks tasks) {
    tasks.lookUp(new MyKey(), MyException.class, ValueOrExceptionSink<MyException>) this);
    return this::processResult;
  }

  @Override
  public acceptValueOrException(@Nullable SkyValue value, @Nullable MyException exception) {
    if (value != null) {
      this.value = (MyValue)value;
      return;
    }
    if (exception != null) {
      this.error = exception;
      return;
    }
    throw new IllegalArgumentException("Both parameters were unexpectedly null.");
  }

  private StateMachine processResult(Tasks tasks) {
    if (exception != null) {
      // Handles the error.
      …
      return DONE;
    }
    // Processes `value`, which is non-null.
    …
  }
}

जैसा कि गड़बड़ी को हैंडल किए बिना लुकअप के साथ किया जाता है, सीधे StateMachine क्लास होने से कॉलबैक लागू करने से लांबा के लिए एक मेमोरी तय होती है.

गड़बड़ी हैंडलिंग से थोड़ी और जानकारी मिलती है, लेकिन ज़रूरी है कि गड़बड़ियों के प्रोपगेशन और सामान्य वैल्यू में ज़्यादा अंतर नहीं है.

एक से ज़्यादा SkyValues का इस्तेमाल करना

अक्सर, एक से ज़्यादा SkyValue लुकअप की ज़रूरत होती है. एक ऐसा तरीका जो ज़्यादातर लोगों की SkyValue के टाइप पर स्विच करने का समय है. नीचे एक उदाहरण दिया गया है, जिसमें इसे प्रोटोटाइप प्रोडक्शन कोड से आसान बनाया गया है.

  @Nullable
  private StateMachine fetchConfigurationAndPackage(Tasks tasks) {
    var configurationKey = configuredTarget.getConfigurationKey();
    if (configurationKey != null) {
      tasks.lookUp(configurationKey, (Consumer<SkyValue>) this);
    }

    var packageId = configuredTarget.getLabel().getPackageIdentifier();
    tasks.lookUp(PackageValue.key(packageId), (Consumer<SkyValue>) this);

    return this::constructResult;
  }

  @Override  // Implementation of `Consumer<SkyValue>`.
  public void accept(SkyValue value) {
    if (value instanceof BuildConfigurationValue) {
      this.configurationValue = (BuildConfigurationValue) value;
      return;
    }
    if (value instanceof PackageValue) {
      this.pkg = ((PackageValue) value).getPackage();
      return;
    }
    throw new IllegalArgumentException("unexpected value: " + value);
  }

Consumer<SkyValue> कॉलबैक को लागू करने की प्रोसेस को साफ़ तौर पर शेयर किया जा सकता है क्योंकि अलग-अलग तरह के मान अलग-अलग होते हैं. जब ऐसा नहीं होता है, तो वापस आकर लैम्डा-आधारित इंप्लिमेंटेशन या पूरी तरह से अंदरूनी-क्लास के इंस्टेंस जो सही कॉलबैक व्यावहारिक होते हैं.

StateMachine के बीच वैल्यू ट्रांसफ़र की जा रही हैं

अब तक, इस दस्तावेज़ में सिर्फ़ यह बताया गया है कि सबटास्क में काम कैसे व्यवस्थित करें, लेकिन सबटास्क के लिए भी कॉलर को वैल्यू की जानकारी भेजनी होगी. क्योंकि सबटास्क ये तर्क के साथ एसिंक्रोनस होते हैं. उनके नतीजों की जानकारी कॉलर को दी जाती है. इसके लिए कॉलबैक. यह काम करने के लिए, सबटास्क एक सिंक इंटरफ़ेस को परिभाषित करता है, जो इंजेक्ट किए जाते हैं.

class BarProducer implements StateMachine {
  // Callers of BarProducer implement the following interface to accept its
  // results. Exactly one of the two methods will be called by the time
  // BarProducer completes.
  interface ResultSink {
    void acceptBarValue(Bar value);
    void acceptBarError(BarException exception);
  }

  private final ResultSink sink;

  BarProducer(ResultSink sink) {
     this.sink = sink;
  }

  … // StateMachine steps that end with this::complete.

  private StateMachine complete(Tasks tasks) {
    if (hasError()) {
      sink.acceptBarError(getError());
      return DONE;
    }
    sink.acceptBarValue(getValue());
    return DONE;
  }
}

इसके बाद, कॉलर StateMachine कुछ ऐसा दिखेगा.

class Caller implements StateMachine, BarProducer.ResultSink {
  interface ResultSink {
    void acceptCallerValue(Bar value);
    void acceptCallerError(BarException error);
  }

  private final ResultSink sink;

  private Bar value;

  Caller(ResultSink sink) {
    this.sink = sink;
  }

  @Override
  @Nullable
  public StateMachine step(Tasks tasks) {
    tasks.enqueue(new BarProducer((BarProducer.ResultSink) this));
    return this::processResult;
  }

  @Override
  public void acceptBarValue(Bar value) {
    this.value = value;
  }

  @Override
  public void acceptBarError(BarException error) {
    sink.acceptCallerError(error);
  }

  private StateMachine processResult(Tasks tasks) {
    // Since all enqueued subtasks resolve before `processResult` starts, one of
    // the `BarResultSink` callbacks must have been called by this point.
    if (value == null) {
      return DONE;  // There was a previously reported error.
    }
    var finalResult = computeResult(value);
    sink.acceptCallerValue(finalResult);
    return DONE;
  }
}

पिछले उदाहरण में इससे जुड़ी कुछ चीज़ें बताई गई हैं. Caller को फिर से खोज नतीजे देता है और अपने Caller.ResultSink के बारे में बताता है. Caller लागू करता है: BarProducer.ResultSink कॉलबैक. फिर से शुरू करने पर, processResult जांच करता है कि क्या कोई गड़बड़ी हुई है या नहीं, यह पता लगाने के लिए value फ़ील्ड खाली है. यह एक सामान्य व्यवहार है पैटर्न, किसी सबटास्क या SkyValue लुकअप से आउटपुट स्वीकार करने के बाद मिलता है.

ध्यान दें कि acceptBarError को लागू करने से नतीजे, गड़बड़ी के बबल की सुविधा के मुताबिक, Caller.ResultSink.

टॉप-लेवल StateMachine के विकल्पों के बारे में Driver में बताया गया है और SkyFunctions पर जोड़ें.

गड़बड़ी ठीक करना

Tasks.lookUp में पहले से ही, गड़बड़ी ठीक करने के कुछ उदाहरण दिए गए हैं कॉलबैक और एक-दूसरे के बीच वैल्यू को ट्रांसफ़र करना StateMachines. अपवाद, इसके अलावा अन्य InterruptedException को फेंका नहीं जाता, बल्कि इसके बजाय पास से गुज़रता है कॉलबैक का इस्तेमाल वैल्यू के तौर पर करते हैं. ऐसे कॉलबैक में अक्सर खास-या सिमैंटिक होता है. पास की जाने वाली कोई वैल्यू या गड़बड़ी हो.

अगले सेक्शन में, Skyframe के साथ अच्छे, लेकिन अहम इंटरैक्शन के बारे में बताया गया है गड़बड़ी ठीक करना.

बबल करने में गड़बड़ी (--nokeep_going)

बबल होने में गड़बड़ी के दौरान, सभी अनुरोध न किए जाने पर भी SkyFunction को रीस्टार्ट किया जा सकता है SkyValues उपलब्ध है. ऐसे मामलों में, बाद वाली स्थिति Tasks API अनुबंध की वजह से पहुंच गए. हालांकि, StateMachine को फिर भी अपवाद लागू करें.

अगला चरण पूरा हो सकता है या नहीं, इस बात पर ध्यान दिए बिना हर स्थिति गड़बड़ी को हैंडल करने वाले कॉलबैक को यह काम करना होगा. अंदर के StateMachine के लिए, ऐसा, पैरंट कॉलबैक को शुरू करके किया जाता है.

टॉप-लेवल StateMachine पर, जो SkyFunction के साथ इंटरफ़ेस करता है, यह ये कर सकता है ValueOrExceptionProducer के setException तरीके को कॉल करके ऐसा किया जा सकता है. इसके बाद ValueOrExceptionProducer.tryProduceValue अपवाद को फेंक देगा, यहां तक कि अगर SkyValues मौजूद न हो.

अगर Driver का इस्तेमाल सीधे तौर पर किया जा रहा है, तो मशीन पर काम न करने के बावजूद, SkyFunction से जनरेट हुई गड़बड़ियां प्रोसेस चल रही है.

इवेंट हैंडलिंग

जिन SkyFunctions को इवेंट उत्सर्जन करने की ज़रूरत होती है उनके लिए, StoredEventHandler इंजेक्ट किया जाता है SkyComputeState में डाला गया और उसे StateMachines में इंजेक्ट किया गया, जहां उन्हें. अब तक, स्काईफ़्रेम के गिरने की वजह से StoredEventHandler की ज़रूरत थी कुछ इवेंट को तब तक नहीं देखा जा सकता, जब तक उन्हें फिर से नहीं चलाया जाता. हालांकि, बाद में इस समस्या को ठीक कर दिया गया. StoredEventHandler इंजेक्शन को सुरक्षित रखा गया है, क्योंकि यह कॉलबैक हैंडल करने में गड़बड़ी की वजह से होने वाले इवेंट को लागू करना.

Drivers और SkyFunctions पर जोड़ना

Driver, StateMachine को लागू करने की ज़िम्मेदारी लेता है, तय रूट StateMachine से शुरू होता है. StateMachine के पास यह करने की अनुमति होती है बार-बार सबटास्क StateMachine में लगाएं. एक Driver इन्हें मैनेज कर सकता है सबटास्क कर सकते हैं. ये सबटास्क एक ट्री स्ट्रक्चर बनाते हैं, जो स्ट्रक्चर्ड एक साथ कई काम करना. Driver बैच SkyValue सबटास्क की खोज करने में मदद मिलती है, ताकि बेहतर तरीके से काम किया जा सके.

Driver की मदद से, नीचे दिए गए एपीआई के साथ कई क्लास बनाई गई हैं.

public final class Driver {
  public Driver(StateMachine root);
  public boolean drive(SkyFunction.Environment env) throws InterruptedException;
}

Driver, पैरामीटर के तौर पर सिंगल रूट StateMachine को लेता है. कॉल से जुड़ी सुविधा Driver.drive, StateMachine को एक्ज़ीक्यूट किया जा सकता है. स्काईफ़्रेम रीस्टार्ट. StateMachine के पूरा और गलत होने पर यह 'सही' दिखाता है नहीं है, तो यह बताता है कि सभी वैल्यू उपलब्ध नहीं हैं.

Driver, StateMachine की समवर्ती स्थिति को बनाए रखता है और यह ठीक है यह SkyKeyComputeState में एम्बेड करने के लिए सही है.

Driver को सीधे तौर पर इंस्टैंशिएट किया जा रहा है

StateMachine को लागू करने का तरीका, नतीजों को इसके ज़रिए पारंपरिक तौर पर बताता है कॉलबैक. Driver को सीधे इंस्टैंशिएट किया जा सकता है, जैसा कि नीचे दिया गया उदाहरण देखें.

Driver को SkyKeyComputeState के साथ-साथ, लागू करने के तरीके में एम्बेड किया गया है संबंधित ResultSink को लागू करना है, ताकि इससे जुड़ी और बेहतर जानकारी दी जा सके नीचे. सबसे ऊपर के लेवल पर, State ऑब्जेक्ट, के नतीजे का अनुमान लगा सकता है, क्योंकि इसके Driver से आउट रहने की गारंटी है.

class State implements SkyKeyComputeState, ResultProducer.ResultSink {
  // The `Driver` instance, containing the full tree of all `StateMachine`
  // states. Responsible for calling `StateMachine.step` implementations when
  // asynchronous values are available and performing batched SkyFrame lookups.
  //
  // Non-null while `result` is being computed.
  private Driver resultProducer;

  // Variable for storing the result of the `StateMachine`
  //
  // Will be non-null after the computation completes.
  //
  private ResultType result;

  // Implements `ResultProducer.ResultSink`.
  //
  // `ResultProducer` propagates its final value through a callback that is
  // implemented here.
  @Override
  public void acceptResult(ResultType result) {
    this.result = result;
  }
}

नीचे दिया गया कोड, ResultProducer को स्केच करता है.

class ResultProducer implements StateMachine {
  interface ResultSink {
    void acceptResult(ResultType value);
  }

  private final Parameters parameters;
  private final ResultSink sink;

  … // Other internal state.

  ResultProducer(Parameters parameters, ResultSink sink) {
    this.parameters = parameters;
    this.sink = sink;
  }

  @Override
  public StateMachine step(Tasks tasks) {
    …  // Implementation.
    return this::complete;
  }

  private StateMachine complete(Tasks tasks) {
    sink.acceptResult(getResult());
    return DONE;
  }
}

फिर, लेज़ी तरीके से नतीजे का पता लगाने के लिए इस्तेमाल किया गया कोड कुछ ऐसा दिख सकता है.

@Nullable
private Result computeResult(State state, Skyfunction.Environment env)
    throws InterruptedException {
  if (state.result != null) {
    return state.result;
  }
  if (state.resultProducer == null) {
    state.resultProducer = new Driver(new ResultProducer(
      new Parameters(), (ResultProducer.ResultSink)state));
  }
  if (state.resultProducer.drive(env)) {
    // Clears the `Driver` instance as it is no longer needed.
    state.resultProducer = null;
  }
  return state.result;
}

Driver को एम्बेड किया जा रहा है

अगर StateMachine से कोई वैल्यू जनरेट होती है और उसमें कोई अपवाद नहीं जोड़ा जाता है, तो एम्बेड करना Driver भी लागू करने का एक और तरीका है, जैसा कि इस उदाहरण में दिखाया गया है.

class ResultProducer implements StateMachine {
  private final Parameters parameters;
  private final Driver driver;

  private ResultType result;

  ResultProducer(Parameters parameters) {
    this.parameters = parameters;
    this.driver = new Driver(this);
  }

  @Nullable  // Null when a Skyframe restart is needed.
  public ResultType tryProduceValue( SkyFunction.Environment env)
      throws InterruptedException {
    if (!driver.drive(env)) {
      return null;
    }
    return result;
  }

  @Override
  public StateMachine step(Tasks tasks) {
    …  // Implementation.
}

SkyFunction में ऐसा कोड हो सकता है जो ऐसा दिखता है (जहां State है फ़ंक्शन के लिए खास टाइप SkyKeyComputeState).

@Nullable  // Null when a Skyframe restart is needed.
Result computeResult(SkyFunction.Environment env, State state)
    throws InterruptedException {
  if (state.result != null) {
    return state.result;
  }
  if (state.resultProducer == null) {
    state.resultProducer = new ResultProducer(new Parameters());
  }
  var result = state.resultProducer.tryProduceValue(env);
  if (result == null) {
    return null;
  }
  state.resultProducer = null;
  return state.result = result;
}

StateMachine लागू करने के तरीके में Driver को एम्बेड करना, इनके लिए बेहतर है SkyFrame की सिंक्रोनस कोडिंग स्टाइल.

अपवाद पैदा करने वाली Stateमशीन

अगर ऐसा नहीं है, तो SkyKeyComputeState एम्बेड किए जा सकने वाले ValueOrExceptionProducer उपलब्ध हैं और ValueOrException2Producer क्लास, जिनमें मिलान करने के लिए सिंक्रोनस एपीआई हैं सिंक्रोनस SkyFunction कोड.

ValueOrExceptionProducer ऐब्सट्रैक्ट क्लास में ये तरीके शामिल हैं.

public abstract class ValueOrExceptionProducer<V, E extends Exception>
    implements StateMachine {
  @Nullable
  public final V tryProduceValue(Environment env)
      throws InterruptedException, E {
    …  // Implementation.
  }

  protected final void setValue(V value)  {  … // Implementation. }
  protected final void setException(E exception) {  … // Implementation. }
}

इसमें, एम्बेड किया गया Driver इंस्टेंस शामिल है और यह एम्बेडिंग ड्राइवर और इंटरफ़ेस में ResultProducer क्लास इस्तेमाल करने का तरीका बताएंगे. ResultSink के बारे में बताने के बजाय, इन दोनों में से कोई भी होने पर, लागू करने के तरीके setValue या setException को कॉल करेंगे. दोनों के होने पर, अपवाद को प्राथमिकता दी जाती है. tryProduceValue तरीका एसिंक्रोनस कॉलबैक कोड को सिंक्रोनस कोड पर सेट करता है और अपवाद के तौर पर तब इस्तेमाल किया जा सकता है, जब कोई सेट हो.

जैसा कि हमने पहले बताया था, गड़बड़ी के बबल होने के दौरान, कोई गड़बड़ी हो सकती है भले ही मशीन अभी तक पूरी न हुई हो, क्योंकि सभी इनपुट उपलब्ध नहीं हैं. यहां की यात्रा पर हूं इसे ध्यान में रखते हुए, tryProduceValue कोई भी सेट अपवाद देता है, यहां तक कि मशीन हो चुकी है.

उपदेश: आखिर में कॉलबैक हटाए जा रहे हैं

StateMachine इस्तेमाल करने का एक बेहतर तरीका है. हालांकि, यह बॉयलरप्लेट पर काफ़ी असर डालने वाले तरीके से काम करता है एसिंक्रोनस कंप्यूटेशन का इस्तेमाल करें. कंटिन्यूअस (खास तौर पर, Runnable के तौर पर) ListenableFuture को पास किए गए हैं) Baze कोड के कुछ हिस्सों में हैं, हालांकि, विश्लेषण SkyFunctions में नहीं होता है. विश्लेषण ज़्यादातर सीपीयू पर निर्भर होता है और डिस्क I/O के लिए कोई कुशल एसिंक्रोनस एपीआई नहीं हैं. आखिरकार, यह होगा बेहतर कॉलबैक को ऑप्टिमाइज़ किया जा सकता है, क्योंकि उनमें सीखने की प्रक्रिया और रुकावट होती है रीडबिलिटी.

Java वर्चुअल थ्रेड, इसका सबसे अच्छा विकल्प है. इसके बजाय कॉलबैक लिखने की ज़रूरत न पड़े, तो सब कुछ सिंक्रोनस, ब्लॉकिंग कॉल. ऐसा इसलिए किया जा सकता है, क्योंकि प्लैटफ़ॉर्म थ्रेड, सस्ता होना चाहिए. हालांकि, वर्चुअल थ्रेड के साथ भी, थ्रेड बनाने और सिंक करने की सुविधा से, आसान सिंक्रोनस ऑपरेशन को बदला जा रहा है प्रिमिटिव बहुत महंगा है. हमने StateMachine से Java वर्चुअल थ्रेड और तेज़ी से लोड होने की वजह से, इनकी संख्या धीमी थी इसमें एंड-टू-एंड विश्लेषण में लगने वाले समय में करीब तीन गुना बढ़ोतरी होती है. वर्चुअल थ्रेड होने की वजह से अब भी झलक सुविधा का इस्तेमाल किया जा सकता है, तो हो सकता है कि यह माइग्रेशन किसी बाद की किसी तारीख को शामिल किया जाता है.

एक और तरीका है, लूम कोरूटीन का इंतज़ार करना. ऐसा कभी भी किया जा सकता है उपलब्ध होने चाहिए. यहां फ़ायदा यह है कि कम की जा सकती है कोऑपरेटिव मल्टीटास्किंग (एक साथ कई काम करना) की सुविधा का इस्तेमाल करके ओवरहेड किया जा सकता है.

अगर बाकी सब कुछ विफल हो जाता है, तो निम्न-स्तरीय बाइटकोड को फिर से लिखना भी एक अच्छा तरीका हो सकता है वैकल्पिक है. पर्याप्त ऑप्टिमाइज़ेशन से, यह लक्ष्य हासिल करना मुमकिन है जो हाथ से लिखे गए कॉलबैक कोड तक पहुंचता है.

अन्य जानकारी

कॉलबैक नरक

कॉलबैक हेल, कॉलबैक का इस्तेमाल करने वाले एसिंक्रोनस कोड में होने वाली एक गंभीर समस्या है. यह इस तथ्य से उठता है कि अगले चरण का अगला चरण नेस्ट किए हुए है क्लिक करें. अगर कई चरणों को पूरा करना है, तो यह नेस्ट करना बहुत मुश्किल गहराई तक. अगर कंट्रोल फ़्लो के साथ कोड का इस्तेमाल किया जाता है, तो कोड मैनेज नहीं किया जा सकेगा.

class CallbackHell implements StateMachine {
  @Override
  public StateMachine step(Tasks task) {
    doA();
    return (t, l) -> {
      doB();
      return (t1, l2) -> {
        doC();
        return DONE;
      };
    };
  }
}

नेस्ट किए गए तरीकों का एक फ़ायदा यह है कि बाहरी चरण को सुरक्षित रखा जा सकता है. Java में, कैप्चर किए गए लैम्डा वैरिएबल सिर्फ़ अंतिम रूप से कारगर साबित होते हैं, इसलिए ऐसे वैरिएबल का उपयोग करना जटिल हो सकता है. डीप नेस्टिंग है इस तरीके के रेफ़रंस को कंटिन्यूअस के तौर पर न दिखाने से बचा गया हैं.

class CallbackHellAvoided implements StateMachine {
  @Override
  public StateMachine step(Tasks task) {
    doA();
    return this::step2;
  }

  private StateMachine step2(Tasks tasks) {
    doB();
    return this::step3;
  }

  private StateMachine step3(Tasks tasks) {
    doC();
    return DONE;
  }
}

runAfter इंजेक्शन लगने पर भी कॉलबैक न हो सकता है पैटर्न का बहुत ज़्यादा इस्तेमाल नहीं किया जाता है, लेकिन इंटरस्पर्सिंग इंजेक्शन के ज़रिए इसे रोका जा सकता है जिसमें एक क्रम में सभी चरण शामिल हों.

उदाहरण: चेन किए गए SkyValue लुकअप

अक्सर ऐसा होता है कि ऐप्लिकेशन लॉजिक के लिए, डिपेंडेंट चेन की ज़रूरत पड़ती है उदाहरण के लिए, अगर दूसरी SkyKey पहले SkyValue पर निर्भर करती है, तो SkyValue में इसका ख्याल रखा जाता है. इस छोटे स्तर पर सोचकर, यह प्रोजेक्ट एक मुश्किल, गंभीर रूप से कॉलबैक स्ट्रक्चर.

private ValueType1 value1;
private ValueType2 value2;

private StateMachine step1(...) {
  tasks.lookUp(key1, (Consumer<SkyValue>) this);  // key1 has type KeyType1.
  return this::step2;
}

@Override
public void accept(SkyValue value) {
  this.value1 = (ValueType1) value;
}

private StateMachine step2(...) {
  KeyType2 key2 = computeKey(value1);
  tasks.lookup(key2, this::acceptValueType2);
  return this::step3;
}

private void acceptValueType2(SkyValue value) {
  this.value2 = (ValueType2) value;
}

हालांकि, कॉन्टिन्यूशन को मेथड रेफ़रंस के तौर पर बताया गया है, इसलिए कोड ऐसा दिखता है ट्रांज़िशन की प्रोसेसर: step2, step1 के बाद आता है. ध्यान दें कि यहां, Lambda का इस्तेमाल, value2 को असाइन करने के लिए किया जाता है. इससे कोड का क्रम मेल खाता है कैलकुलेशन का क्रम ऊपर से नीचे तक होगा.

अन्य सलाह

पठनीयता: निष्पादन आदेश

StateMachine.step को लागू करते रहने के लिए, ताकि इसे पढ़ने में आसानी हो उसके ठीक बाद, एक्ज़ीक्यूशन ऑर्डर और कॉलबैक लागू करते समय, कोड में पास किए जाते हैं. जहां भी कंट्रोल फ़्लो मौजूद है वहां हमेशा ऐसा करना मुमकिन नहीं होता शाखाएं. ऐसे मामलों में अतिरिक्त टिप्पणियां मददगार हो सकती हैं.

उदाहरण: चेन्ड स्काईवैल्यू लुकअप में, एक इसे पाने के लिए, इंटरमीडिएट मेथड रेफ़रंस बनाया जाता है. यह शेयर की गई कीमत पर क्षमता के बारे में बात करते हैं, जो शायद यहां काम का हो.

जेनरेशनल हाइपोथीसिस

थोड़े समय तक रहने वाले Java ऑब्जेक्ट, Java की पीढ़ी वाली हाइपोथीसिस को तोड़ते हैं गार्बेज कलेक्टर, जिसे ऐसी चीज़ों को संभालने के लिए डिज़ाइन किया गया है जो या ऐसी चीज़ें जो हमेशा चलें. परिभाषा के अनुसार, इसमें मौजूद ऑब्जेक्ट SkyKeyComputeState इस अनुमान का उल्लंघन करता है. ऐसी वस्तुएं, जिनमें Driver पर रूट किए गए सभी StateMachine का बनाया हुआ ट्री एसिंक्रोनस कंप्यूटेशन का इंतज़ार करते हुए, निलंबित होने पर एक इंटरमीडिएट लाइफ़ पूरा करना है.

यह JDK19 में कम खराब लगता है, लेकिन StateMachine का इस्तेमाल करते समय, यह कभी-कभी जीसी टाइम में बढ़ोतरी दिख सकती है, भले ही जनरेट किया गया ग़ैर-ज़रूरी डेटा भी शामिल है. StateMachine की अवधि थोड़ी देर के लिए होती है उन्हें पुरानी जनरेशन में प्रमोट किया जा सकता है. इससे यह तेज़ी से भरी जा सकती है. इसलिए, साफ़ करने के लिए ज़्यादा महंगे मेजर या पूरे जीसी की ज़रूरत होती है.

शुरुआती तौर पर, StateMachine वैरिएबल का इस्तेमाल कम करना है, लेकिन यह हमेशा संभव नहीं होता है, उदाहरण के लिए, अगर एक से ज़्यादा राज्य. जहां मुमकिन हो वहां लोकल स्टैक step वैरिएबल, युवा पीढ़ी का होता है और GC' का इस्तेमाल करें.

StateMachine वैरिएबल के लिए, चीज़ों को सबटास्क में बांटें और इन चीज़ों को फ़ॉलो करें के बीच मानों का प्रसार करने के लिए सुझाया गया पैटर्न StateMachine का इस्तेमाल करना भी मददगार होता है. ध्यान से देखो कि कब पैटर्न का इस्तेमाल करते समय, सिर्फ़ चाइल्ड StateMachine के पास पैरंट ग्रुप के रेफ़रंस हैं StateMachines और इसके उलट नहीं. इसका मतलब है कि जब बच्चा इन कामों को पूरा करता है और नतीजे के कॉलबैक का इस्तेमाल करके माता-पिता को अपडेट करते हैं, तो बच्चे स्वाभाविक रूप से के दायरे में आता है और GC के लिए ज़रूरी शर्तें पूरी करता है.

आखिर में, कुछ मामलों में, पहले की स्थितियों में StateMachine वैरिएबल की ज़रूरत होती है लेकिन बाद की स्थितियों में नहीं. बड़े साइज़ के रेफ़रंस को हटाने से फ़ायदा हो सकता है ऑब्जेक्ट को बताए जाने के बाद पता चलता है कि अब उनकी ज़रूरत नहीं है.

नाम की स्थितियां

किसी तरीके का नाम रखते समय, आम तौर पर व्यवहार के लिए किसी तरीके को नाम दिया जा सकता है जो उसी तरीके से होती है. मुझे समझ नहीं आया कि इसे कैसे करना है कोई स्टैक मौजूद नहीं है, इसलिए StateMachine. उदाहरण के लिए, मान लें कि विधि foo सब-तरीका bar पर कॉल करता है. StateMachine में, इसका अनुवाद राज्य का क्रम foo, इसके बाद bar. foo में अब यह व्यवहार शामिल नहीं है bar. इस वजह से, राज्यों के लिए तरीकों के नाम कम होते हैं. जिसमें संभावित तौर पर स्थानीय व्यवहार दिख रहा हो.

कॉन करंसी ट्री का डायग्राम

नीचे दिए गए डायग्राम का दूसरा व्यू स्ट्रक्चर्ड रिपोर्ट में दिया गया है Concurrency जो ट्री संरचना को बेहतर ढंग से दिखाता है. इन ब्लॉक से एक छोटा पेड़ बनता है.

स्ट्रक्चर्ड कॉनकरेंसी 3D


  1. शुरू से रीस्टार्ट होने के स्काईफ़्रेम के कन्वेंशन के उलट जब वैल्यू उपलब्ध नहीं हैं.

  2. ध्यान दें कि step को InterruptedException फेंकने की अनुमति है, लेकिन उदाहरणों में इसे छोड़ देते हैं. Baze कोड में कुछ कम तरीके होते हैं जिनकी मदद से शामिल है और यह Driver तक लागू होता है, बाद में इसकी जानकारी दी जाएगी, जो StateMachine चलाती है. किसी इसकी ज़रूरत नहीं.

  3. एक ही समय पर पूरे किए जाने वाले सबटास्क ConfiguredTargetFunction से प्रेरित थे, हर डिपेंडेंसी के लिए इंडिपेंडेंट काम करता है. हेर-फेर करने के बजाय सभी डिपेंडेंसी को एक साथ प्रोसेस करने वाले जटिल डेटा स्ट्रक्चर, कमियां पेश करते हैं, हर डिपेंडेंसी अपने-आप होती है StateMachine.

  4. एक ही चरण में होने वाले कई tasks.lookUp कॉल को बैच बनाकर भेजा जाता है. एक साथ कई बैच बनाने की सुविधा, एक ही समय में होने वाले लुकअप के हिसाब से बनाई जा सकती है में सबटास्क कर सकते हैं.

  5. सैद्धांतिक तौर पर, यह Java की स्ट्रक्चर्ड कं करंसी के जैसा है jeps/428.

  6. ऐसा करना, किसी थ्रेड को शुरू करने और उसे जोड़ने जैसा ही है क्रम में चलने वाला कंपोज़िशन.