قد يكون الأصدقاء الذين استخدموا حزم التزامن Java على دراية بالمستقبل (الواجهة). يتم دعم المستقبل بشكل مباشر على مستوى بناء الجملة في بعض لغات المجال (مثل Alice ML).
هنا سوف نأخذ java.util.concurrent.future كمثال للتحدث بإيجاز عن طريقة العمل المحددة في المستقبل. يمكن اعتبار الكائن المستقبلي نفسه مرجعًا صريحًا ، وهو إشارة إلى نتائج المعالجة غير المتزامنة. نظرًا لطبيعته غير المتزامنة ، قد لا يكون الكائن الذي يشير إليه متاحًا في بداية الإنشاء (على سبيل المثال ، لا يزال قيد التشغيل أو نقل الشبكة أو الانتظار). في هذا الوقت ، إذا لم يكن تدفق البرنامج الذي يحصل على المستقبل في عجلة من أمره لاستخدام الكائن المشار إليه في المستقبل ، فيمكنه فعل أي شيء آخر تريده. كن حالتين:
آمل أن أرى هذا الكائن متاحًا وإكمال بعض عمليات المتابعة ذات الصلة. إذا لم يكن متاحًا حقًا ، فيمكنك أيضًا إدخال عمليات فرع أخرى.
"بدونك ، ستفقد حياتي معناها ، لذلك حتى لو اختفى البحر ، سأنتظرك." -وقت)
بالنسبة للحالة السابقة ، يمكنك تحديد ما إذا كان الكائن المشار إليه جاهزًا عن طريق الاتصال بـ Future.isdone () واتخاذ معالجة مختلفة ؛
احصل على (فترة طويلة ، وحدة الوقت) تنتظر أن يكون الكائن جاهزًا عن طريق الحظر المتزامن. ما إذا كان يتم حظر وقت التشغيل الفعلي أو إرجاعه على الفور يعتمد على وقت استدعاء GET () وترتيب كائن جاهز.
ببساطة ، يمكن للوضع المستقبلي تلبية احتياجات التزامن القائمة على البيانات في العمليات المستمرة ، وليس فقط الحصول على تحسينات في الأداء في التنفيذ المتزامن ، ولكن أيضًا بساطة وأناقة العمليات المستمرة.
مقارنة مع أنماط التصميم المتزامنة الأخرى
بالإضافة إلى المستقبل ، تتضمن أنماط تصميم التزامن الشائعة الأخرى "رد الاتصال (في بيئة متعددة الخيوط)" ، "الرسائل/الأحداث المدفوعة (في نموذج الممثل)" ، إلخ.
يعتبر رد الاتصال هو وضع التزامن غير المتزامن الأكثر شيوعًا ، والذي يحتوي على تصميم فوري ومواجهة بسيطة. ولكن بالمقارنة مع المستقبل ، فإن عيوبها واضحة للغاية. أولاً ، يتم تنفيذ عمليات الاسترجاعات في بيئات Multihdered بشكل عام في مؤشر ترابط الوحدة النمطية التي تثير رد الاتصال ، مما يعني أن مشكلات الاستبعاد المتبادلة في مؤشر الترابط يجب أن تكون عند كتابة طرق رد الاتصال ثانياً ؛ تنفيذ عمليات الاسترداد لتطبيقات المستخدمين ، والتي هي أيضًا غير آمنة نسبيًا ، لأنه لا يمكنك تحديد المدة التي سيستغرقها أو ما هي الاستثناءات التي ستحدث ، والتي قد تؤثر بشكل غير مباشر على فوري وموثوقية هذه الوحدة ؛ التسلسل. لذلك ، فإن واجهة رد الاتصال مناسبة للسيناريوهات حيث يجب إكمال المهام البسيطة فقط في رد الاتصال ولا يجب دمجها مع عمليات أخرى.
عيوب أوضاع رد الاتصال أعلاه هي بالضبط نقاط القوة في المستقبل. نظرًا لأن استخدام المستقبل هو دمج برامج تشغيل البيانات غير المتزامنة بشكل طبيعي في عمليات متسلسلة ، لا يتعين عليك التفكير في مشكلات Mutex على الإطلاق. يذكر أدناه "Lazy Future"). من ناحية أخرى ، فإن الوحدات النمطية التي توفر واجهات مستقبلية لا يجب أن تقلق بشأن مشكلات الموثوقية مثل واجهات رد الاتصال وتأثيرها الفوري المحتمل على هذه الوحدة.
نمط تصميم متزامن شائع آخر هو "الرسائل (حدث) مدفوع" ، والذي يستخدم عمومًا في نموذج الممثل: يرسل طالب الخدمة رسالة إلى مزود الخدمة ، ثم يواصل أداء المهام اللاحقة التي لا تعتمد على نتائج معالجة الخدمة ويعتمد على ذلك إذا كنت بحاجة إلى الاعتماد عليها. على الرغم من أن التحكم المتزامن المستند إلى آلة الحالة هذا أكثر ملاءمة للعمليات المتسلسلة للاستمرارية من عوامل الاسترجاعات ، فإن المطورين يتعين عليهم خفض العملية المستمرة إلى عمليات فرعية متعددة خاصة بالدولة وفقًا لمادة الخدمة غير المتزامنة ، مما يزيد بشكل مصطنع من تعقيد التطوير. يمكن أن يؤدي استخدام الوضع المستقبلي إلى تجنب هذه المشكلة ولا يتعين عليهم كسر العمليات المستمرة للمكالمات غير المتزامنة. ومع ذلك ، تجدر الإشارة إلى شيء واحد: قد تمنع طريقة المستقبل. (يمكن لنموذج الممثل القائم على كوروتين حل هذا الصراع بشكل أفضل)
تنعكس مرونة المستقبل أيضًا في اختياره الحر بين التزامن والخيارات غير المتزامنة. احتياجات العملية. على سبيل المثال ، يمكنك أن تقرر ما إذا كنت تريد استخدام هذه الفجوة لإكمال المهام الأخرى بناءً على ما إذا كانت البيانات جاهزة ، وهي مريحة تمامًا لتنفيذ آلية "التنبؤ غير المتزامن للفرع".
مشتق المستقبل
بالإضافة إلى النماذج الأساسية المذكورة أعلاه ، فإن Future لديه أيضًا تغييرات مشتقة غنية ، لذلك فيما يلي بعض الأشكال الشائعة.
مستقبل كسول
على عكس العقود الآجلة العامة ، لا يبدأ Lazy Future بنشاط في إعداد الكائن المشار إليه في بداية الإنشاء ، لكنه ينتظر حتى يتم طلب الكائن قبل بدء العمل المقابل. لذلك ، لا يهدف المستقبل الكسول نفسه إلى تحقيق التزامن ، ولكنه يأخذ توفير موارد الحوسبة غير الضرورية كنقطة انطلاق ، وتأثيره يشبه Lambda/الإغلاق. على سبيل المثال ، عند تصميم واجهات برمجة التطبيقات معينة ، قد تحتاج إلى إرجاع مجموعة من المعلومات ، وقد يستهلك حساب بعضها موارد كبيرة. ومع ذلك ، قد لا يشعر المتصل بالقلق إزاء كل هذه المعلومات ، لذا فإن توفير الكائنات التي تتطلب المزيد من الموارد في شكل مستقبل كسول يمكن أن يوفر الموارد عندما لا يحتاج المتصل إلى استخدام معلومات محددة.
بالإضافة إلى ذلك ، يمكن أيضًا استخدام Lazy Future لتجنب الاستثناءات المتبادلة غير الضرورية الناجمة عن الاستحواذ المبكرة أو قفل الموارد.
يعد
يمكن اعتبار الوعد فرعًا خاصًا للمستقبل المشترك. ولكن يتم استخدام الوعد لتمثيل السيناريوهات صراحة حيث لا يتم تشغيل العمليات غير المتزامنة مباشرة من قبل المتصل الخدمة. على سبيل المثال ، لا يتم تشغيل التحكم في توقيت الواجهة المستقبلية المشترك ، ولكن من قبل المشترك. لذلك ، مقارنة بالمستقبل القياسي ، تحتوي واجهة الوعد بشكل عام على مجموعة إضافية () أو واجهة الوفاء ().
المستقبل القابل لإعادة الاستخدام
المستقبل العادي هو لمرة واحدة ، مما يعني أنه عندما تحصل على نتائج معالجة غير متزامنة ، يفقد الكائن المستقبلي نفسه معناها. ولكن يمكن أيضًا إعادة استخدام المستقبل المصمم خصيصًا ، وهو أمر مفيد للغاية للبيانات التي يمكن تغييرها عدة مرات. على سبيل المثال ، تتيح الواجهة المستقبلية التي توفرها إطار الاشتراك الموزعة Taobao المذكورة أعلاه إلى WaitNext () طريقة (ما يعادل المستقبل ()). آخر مكالمة. ميزة هذا التصميم هي أن مستخدم الواجهة يمكن أن يستجيب للتغيرات في بيانات الاشتراك في أي وقت مناسب ، أو ببساطة من خلال حلقة لا حصر لها في مؤشر ترابط مستقل ، مع مراعاة مهام التوقيت الأخرى ، أو حتى انتظار مهام متعددة في نفس الوقت. أمثلة مبسطة هي كما يلي:
لـ (؛؛) .}} doscheduledtask () ؛}
استخدام المستقبل
أولاً ، دعنا ندرج رمزًا في Java.
//: concurrency/callablemo.javaimport java.util.concurrent Call () {return "نتيجة TaskWithresult" + id ؛ ArrayList <future <string> () ؛ يحاول : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : ::::::::::::::::::::::::: :::::::::::::::::::::: ::::::::::::::::::::::::::::::: {// get () حتى الانتهاء: system.println (fs.get ()) ؛ : نتيجة TaskWithresult 0result of taskWithresult 1result of taskWithresult 2res ult of taskWithresult 3results of taskwithresult 4resultsultresult 5resultult of taskWithresult 6resultult of taskWithresult 7result of taskwithresultلشرح استخدام المستقبل ، أولاً ، فإن كائن EXEC SEVILLORSRIVICE EXEC SRIPPHT () لإنشاء كائن مستقبلي ، يستخدم نوعًا محددًا لنتيجة الإرجاع القابلة للاتصال للتعليم. يمكنك استخدام طريقة ISDONE () للاستعلام عما إذا كان المستقبل قد اكتمل. عند اكتمال المهمة ، يكون لها نتيجة ، ويمكنك استدعاء طريقة GET () للحصول على النتيجة. يمكنك أيضًا استدعاء GET () مباشرة بدون فحص ISDONE (). يمكنك استدعاء وظيفة GET () مع مهلة ، أو استدعاء ISDONE () أولاً لمعرفة ما إذا كانت المهمة قد اكتملت ، ثم اتصل على ().