إطار الشوكة/JOIN هو تنفيذ واجهة SecorrosorService ، والتي من خلالها يمكننا تنفيذ عمليات متعددة. يمكن استخدام Fork/Join لتقسيم مهمة كبيرة بشكل متكرر إلى مهام صغيرة متعددة ، بهدف الاستفادة الكاملة من جميع الموارد لتعزيز أداء التطبيق قدر الإمكان.
مثل أي تطبيق واجهة ExecutorService ، يستخدم Fork/Join أيضًا تجمعات مؤشرات الترابط لإدارة مؤشرات ترابط العمال بتوزيع. ما هو فريد من نوعه في إطار الشوكة/الانضمام هو أنه يستخدم خوارزمية سرقة العمل. من خلال هذه الخوارزمية ، يمكن لخيوط العمال سرقة مهام مؤشرات الترابط المزدحمة الأخرى لتنفيذها عندما لا يمكن القيام بأي شيء.
جوهر Fork/Join Framework هو فئة Forkjoinpool ، وهي فئة فرعية من فئة AbstractExecutorService. يقوم Forkjoinpool بتنفيذ خوارزمية سرقة العمل الأساسية ويمكنها إجراء معالجة ForkJointask.
الاستخدام الأساسي
تتمثل الخطوة الأولى في استخدام Fork/Join Framework في كتابة التعليمات البرمجية التي تؤدي مهام مجزأة. يشبه الرمز المراد كتابته الرمز الزائف التالي:
إذا كانت المهمة صغيرة بما يكفي: قم بتنفيذ المهمة مباشرةً: قم بقطع المهمة إلى مهامتين صغيرتين لتنفيذ مهامتين صغيرتين وانتظر النتيجة
استخدم الفئة الفرعية ForkJointask لتغليف الكود على النحو الوارد أعلاه. عادةً ما يتم استخدام بعض الفصول التي توفرها JDK ، بما في ذلك Recursivetask (ستعود هذه الفئة إلى نتيجة) و RecursiveAction.
بعد إعداد الفئة الفرعية ForkJointask ، قم بإنشاء كائن يمثل جميع المهام ونقله إلى طريقة Invoke () لمثيل ForkJoinPool.
من طمس إلى واضح
للمساعدة في فهم كيفية عمل Fork/Join Framework ، نستخدم حالة لتوضيح: على سبيل المثال ، غير وضوح صورة. نحن نمثل الصورة باستخدام صفيف عدد صحيح ، حيث تمثل كل قيمة رقمية لون بكسل. يتم تمثيل الصورة غير الواضحة أيضًا بمجموعة من نفس الطول.
يتحقق تنفيذ التمزق عن طريق معالجة كل بكسل يمثل الصورة. احسب متوسط كل بكسل والبكسلات المحيطة به (متوسط الألوان الأساسية الثلاثة للأحمر والأصفر والأزرق) ، والمجموعة الناتجة من النتائج هي الصورة غير الواضحة. نظرًا لأن تمثيل الصور عادةً ما يكون صفيفًا كبيرًا ، فإن العملية بأكملها عادة ما تستغرق الكثير من الوقت. يمكن استخدام Fork/Join Framework للاستفادة من مزايا المعالجة المتزامنة على الأنظمة متعددة المعالجات لتسريعها. هنا تطبيق محتمل:
حزمة com.zhyea.robin ؛ استيراد java.util.concurrent.recursiveaction ؛ يمتد الفئة العامة forkblur recursiveaction {private int [] msource ؛ خاص int mstart ؛ Private int mlength ؛ private int [] mdestination ؛ // مقبض حجم النافذة ؛ يجب أن يكون رقمًا غريبًا. private int mblurwidth = 15 ؛ Forkblur العام (int [] src ، int start ، int ، int [] dst) {msource = src ؛ mStart = ابدأ ؛ الطول = الطول ؛ mdestination = DST ؛ } void void محمية compedirectly () {int sidepixels = (mblurwidth - 1) / 2 ؛ لـ (int index = mStart ؛ index <mstart+mlength ؛ index ++) {// احسب القيمة المتوسطة. float rt = 0 ، gt = 0 ، bt = 0 ؛ لـ (int mi = -sidepixels ؛ mi <= sidepixels ؛ mi ++) {int mindex = math.min (math.max (mi+index ، 0) ، msource.length - 1) ؛ int pixel = msource [mindex] ؛ RT += (Float) ((Pixel & 0x00FF0000) >> 16) / Mblurwidth ؛ gt += (float) ((pixel & 0x00000ff00) >> 8) / mblurwidth ؛ BT += (Float) ((Pixel & 0x000000fff) >> 0) / mblurwidth ؛ } // إعادة تنظيم البكسل المستهدف. int dpixel = (0xFF0000000) | (((int) rt) << 16) | (((int) gt) << 8) | (((int) bt) << 0) ؛ mdestination [الفهرس] = dpixel ؛ }} ....}الآن قم بتنفيذ طريقة COMPUTE () ، حيث يتم تنفيذ كلتا العمليتين الغامضتين ، ويتم تنفيذ تقسيم المهمة إلى مهامتين صغيرتين. هنا نقرر ببساطة ما إذا كان سيتم تنفيذ المهمة مباشرة أو تقسيمها إلى مهمتين صغيرتين بناءً على طول المصفوفة:
محمية ثابت int sthreshold = 100000 ؛ compute void المحمي () {if (mlength <sthreshold) {computedirectly () ؛ يعود؛ } int split = mlength / 2 ؛ InvokeAll (New Forkblur (Msource ، Mstart ، Split ، Mdestination) ، New Forkblur (msource ، mstart + split ، mlength - split ، mdestination)) ؛ }نظرًا لأن تنفيذ الأساليب المذكورة أعلاه محددة في فئة فرعية من Recursiveact ، يمكن إنشاء المهام وتشغيلها مباشرة في ForkJoinPool. الخطوات المحددة هي كما يلي:
1. إنشاء كائن يمثل المهمة المراد تنفيذها:
يمثل // SRC مجموعة من وحدات البكسل من الصورة المصدر // DST تمثل وحدات البكسل الخاصة بالتقاط الصورة المولدة FB = New Forkblur (SRC ، 0 ، SRC.Length ، DST) ؛
2. قم بإنشاء مثيل forkjoinpool الذي يدير المهمة:
ForkJoinPool pool = new ForkJoinPool();
3. قم بتشغيل المهمة:
pool.invoke(fb);
يحتوي الرمز المصدر أيضًا على بعض التعليمات البرمجية لإنشاء الصورة الهدف. للحصول على تفاصيل ، راجع مثال Forkblur.
التنفيذ القياسي
لاستخدام Fork/Join Framework لتنفيذ المهام المتزامنة على أنظمة متعددة النواة وفقًا للخوارزميات المخصصة ، بالطبع ، تحتاج إلى تنفيذ فئات مخصصة (مثل فئة Forkblur التي قمنا بتنفيذها من قبل). بالإضافة إلى ذلك ، تم استخدام بعض ميزات Fork/Join Framework على نطاق واسع في Javase. على سبيل المثال ، تستخدم طريقة Parallelsort () من فئة java.util.arrays في Java8 إطار الشوكة/Join. للحصول على التفاصيل ، يرجى الرجوع إلى وثائق Java API.
هناك تطبيق آخر لإطار الشوكة/الانضمام هو تحت حزمة java.util.streams ، والتي تعد أيضًا جزءًا من ميزة Lambda في Java8.