جدولة Coroutine المتزامنة
بعد تعلم قناة وظيفة الاتصال في coroutine ، تحدثنا بعد ذلك عن وظيفة WaitGroup. في الواقع ، هي نفسها أداة جدولة coroutine. لن ندخل في تفاصيل حول وظيفتها ، فبعد كل شيء ، أوضح المقال السابق ذلك تمامًا. اليوم ، سنستمر في موضوع WaitGroup وسنواصل الحديث عن الجدولة المتزامنة لـ coroutines.
تنفيذ Coroutine وحاويات coroutine
بعد تعلم هذا ، لا أعرف ما إذا كنت قد وجدت مشكلة ، أي إذا لم تكن في حاوية coroutine ، وإذا تمت مصادفة عملية حظر ، فسيتم تنفيذ coroutine بالتتابع. وإذا كان في حاوية coroutine ، فإنه يصبح تنفيذًا متزامنًا.
go(function(){
sleep(2);
echo "cid1:" . Co::getCid() , PHP_EOL;
});
go(function(){
sleep(1);
echo "cid2:" . Co::getCid() , PHP_EOL;
});
//cid1:1
//cid2:2
في كود الاختبار أعلاه ، يستريح coroutine الأول لمدة ثانيتين ، ويستريح الثاني لمدة ثانية واحدة ، ويتم تنفيذ نتائج الإخراج النهائية بالتتابع. بعد ذلك نضعه في حاوية coroutine.
\Swoole\Coroutine\run(function(){
go(function(){
sleep(2);
echo "cid1:" . Co::getCid() , PHP_EOL;
});
go(function(){
sleep(1);
echo "cid2:" . Co::getCid() , PHP_EOL;
});
});
//cid2:3
//cid1:2
في حاوية coroutine ، ينفذ coroutine الثاني أولاً ويخرج المحتوى. من الواضح أن هذه حالة تشبه إلى حد بعيد العملية المتوازية. فهل هذا هو الحال في الواقع؟
في الواقع ، يجب شرح هذا الجزء من المحتوى في coroutine بنقرة واحدة ، لكنني أخشى أن يكتشف الأصدقاء الأذكياء هذه المشكلة مقدمًا ، لذلك سأقولها هنا بإيجاز مقدمًا.
في الواقع ، الكوروتين ليس متوازيًا ، أعتقد أن الجميع يعرف هذا بالفعل. لقد قلنا ذلك مرات عديدة. تعمل Coroutines على الخيوط ، و Swoole هي عملية ذات خيط. لا تمتلك Coroutines إمكانات متوازية ، ولكن يتم تنفيذها بشكل متزامن مثل الوظائف. ومع ذلك ، فهي في وضع المستخدم ، ويمكننا تعليقها واستئنافها يدويًا ، وهي القدرة على العائد () واستئناف () التي تعلمناها من قبل. لذلك ، يمكن استخدام هذه الميزة للتبديل بسرعة إلى coroutines أخرى للمعالجة أثناء انتظار IO ، ثم العودة لمواصلة معالجة محتويات هذا coroutine عندما ينتهي IO هنا.
تقوم حاوية coroutine في الواقع بتنفيذ مجموعة من بيئة تنفيذ coroutine الداخلية ، بحيث يمكن أن تكون العديد من الرموز التي تم تنفيذها في الأصل بشكل متزامن غير متزامنة في الحاوية. يمكننا أيضًا استخدام co :: sleep () خارج الحاوية لتعليق العمليات المتزامنة ، ولكن داخل الحاوية ، يمكن تفعيل sleep () مباشرة. بالإضافة إلى ذلك ، في Swoole ، النوم () ليس شيئًا جيدًا ، فقد نستخدمه كثيرًا للتوضيح ، ولكن في سيناريوهات تطوير الأعمال الحقيقية ، من الأفضل عدم استخدامه. للسبب ، يرجى الرجوع إلى Swoole Programming Notes https://wiki.swoole.com/#/getting_started/notice؟id=sleepusleep Impact .
سنتحدث عن هذا بالتفصيل في آخر كوروتين بنقرة واحدة من فصل coroutine. تم شرح المحتوى المتعلق بالتوازي والتزامن أيضًا في المقالة الأولى من العملية المبكرة. إذا كنت لا تتذكر ، فتذكر العودة وقراءتها.
جدولة أبسط من WaitGroup
نظرًا لاستخدام coroutines ، نحتاج بالتأكيد إلى إمكانات التزامن ، وقد تؤدي العمليات المتزامنة إلى حدوث بعض المشكلات. في الواقع ، هو نتيجة التنفيذ المتزامن للعديد من الأعمال التي تحدثنا عنها في المرة السابقة. في ذلك الوقت ، استخدمنا WaitGroup لتحقيق تأثير انتظار coroutines متعددة لإكمال الإرجاع المتزامن. ولكن في Swoole ، يتم أيضًا توفير أداة أبسط تسمى Barrier.
\Swoole\Coroutine\run(function () {
$time = microtime(true);
$barrier = \Swoole\Coroutine\Barrier::make();
foreach (range(1, 4) as $i) {
go(function () use ($barrier, $i) {
\Swoole\Coroutine\System::sleep($i);
});
}
\Swoole\Coroutine\Barrier::wait($barrier);
echo microtime(true) - $time, PHP_EOL;
});
// 4.0022649765015
في الواقع ، لها نفس خصائص WaitGroup ، ولكنها تحفظ بعض الخطوات. كما ترى من الكود ، لا يتطلب مكون الأداة هذا الإضافة اليدوية () والعملية (). لاستخدامه ، نحتاج فقط أولاً إلى إنشاء () كائن ، ثم تمرير الكائن إلى coroutine عبر الاستخدام. طالما أن هذا الكائن الحاجز قيد الاستخدام ، فسيبدأ العد تلقائيًا. عندما ينتهي coroutine من التنفيذ ، فإنه سيتم تلقائيا (). أخيرًا ، يمكننا استخدام طريقة Barrier wait () للانتظار والاستماع.
هل يبدو الأمر أكثر ملاءمة من WaitGroup؟ إذا كان هناك العديد من coroutines ، فيمكنك كتابة أساليب add () و done () أقل بكثير.
تطبيق Coroutine والجدولة على خادم غير متزامن
لقد أوضحنا دائمًا coroutines في سطر الأوامر من قبل ، ولكن في الواقع ، يتم استخدامه بنفس الطريقة في تطبيقات الخادم ، ويمكن أيضًا جدولة coroutines بنفس الطريقة.
$serv = new Swoole\Http\Server("0.0.0.0", 9501, SWOOLE_PROCESS);
$serv->on('request', function ($req, $resp) {
$time = microtime(true);
$wg = new \Swoole\Coroutine\WaitGroup();
$wg->add();
$wg->add();
$res = 1;
go(function () use ($wg, &$res) {
co::sleep(3);
$res += 1;
$wg->done();
});
go(function () use ($wg, &$res) {
co::sleep(4);
$res *= 10;
$wg->done();
});
$wg->wait();
$endTime = microtime(true) - $time;
$resp->end($res . " - " . $endTime);
});
$serv->start();
//20 - 4.002151966095
في الفقرة أعلاه ، نحن ننتظر بشكل متزامن من خلال WaitGroup. يمكنك محاولة استبداله بـ Barrier لرؤية التأثير.
لخص
محتوى اليوم بسيط نسبيًا ، بعد كل شيء ، بعد أن أصبح لدينا الأساس السابق ، سيصبح من الصعب علينا تعلم وفهم المفاهيم الجديدة أقل وأقل. أهم شيء هو فهم مفهوم التنفيذ غير المتزامن والعودة المتزامنة ، وفهم سبب القيام بذلك. يمكن البحث في هذه المعلومات الإضافية عن المحتوى المتعلق بـ Promise في JS المذكور سابقًا.
كود الاختبار:
https://github.com/zhangyue0503/swoole/blob/main/4.Swoole٪E5٪8D٪8F٪E7٪A8٪8B/source/4.5٪E5٪8D٪8F٪E7٪A8٪8B٪E5٪ B9٪ B6٪ E5٪ 8F٪ 91٪ E8٪ B0٪ 83٪ E5٪ BA٪ A6.php
الوثائق المرجعية:
https://wiki.swoole.com/#/coroutine/barrier
https://wiki.swoole.com/#/coroutine/multi_call؟