0Pricing
PHP Academy · درس

نموذج التزامن في PHP

افهم عمليات الإدخال والإخراج الحاجبة والمواضع التي تفيد فيها العمليات غير المتزامنة.

نموذج التزامن في PHP درس مجاني في PHP Academy على CoddyKit. هذا هو الدرس 1 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في PHP Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة PHP Academy 4 دروس في المجموع.

PHP متزامنة افتراضياً

تشغّل PHP التقليدية طلباً واحداً لكل عملية، من البداية إلى النهاية، مع إدخال/إخراج حاجب. يؤدي استدعاء file_get_contents() لواجهة API بطيئة إلى تجميد النص البرمجي بأكمله حتى وصول البيانات. ونموذج عدم مشاركة الحالة (عملية جديدة لكل طلب، وإزالة الحالة في النهاية) بسيط للغاية، لكنه يعني أن العامل الواحد لا يستطيع تنفيذ أكثر من شيء واحد في الوقت نفسه. يوضّح هذا الدرس المواضع التي يسبب فيها ذلك مشكلة، والمواضع التي يفيد فيها التنفيذ غير المتزامن.

قياس الإدخال/الإخراج الحاجب

راقبوا زمن الساعة الفعلي الذي يهيمن عليه الانتظار لا الحساب. تستغرق ثلاثة طلبات متسلسلة، مدة كل منها ثانية واحدة، نحو 3 ثوانٍ، رغم أن المعالج يكون خاملاً طوال الوقت.

<?php
$start = microtime(true);
foreach (['a', 'b', 'c'] as $job) {
    usleep(1_000_000); // simulate a 1s blocking network call
    echo "done $job\n";
}
printf("elapsed: %.2fs\n", microtime(true) - $start); // ~3.00s

مرتبط بالمعالج مقابل مرتبط بالإدخال/الإخراج

لا يفيد التزامن إلا في الأعمال المرتبطة بالإدخال/الإخراج، أي الوقت الذي يُقضى في انتظار الشبكة أو القرص أو قاعدة البيانات. أما الأعمال المرتبطة بالمعالج (التجزئة، وتغيير حجم الصور، والتحليل) فغالباً ما يكون الخيط الواحد فيها مستنفداً بالكامل؛ ولا يضيف التنفيذ غير المتزامن سوى كلفة جدولة. شخّصوا المشكلة أولاً:

  • استدعاءات HTTP أو استعلامات قاعدة بيانات بطيئة كثيرة ← يفيد التنفيذ غير المتزامن كثيراً.
  • حلقات حسابية كثيفة ← استخدموا التوازي (العمليات/الخيوط) لا حلقة الأحداث.

كيف توسّعت PHP حتى الآن

توسّعت PHP تاريخياً باستخدام التزامن على مستوى العمليات: إذ تحافظ PHP-FPM على مجموعة من العمليات العاملة، وتتولى كل عملية طلباً واحداً في كل مرة، بينما يوزّع نظام التشغيل العمل بينها. وهذا تزامن حقيقي بين الطلبات، لكنه لا يقدّم شيئاً داخل الطلب؛ فلا يزال يتعذر عليكم توزيع 50 استدعاءً لواجهات API بالتوازي داخل معالج واحد باستخدام الشيفرة الحاجبة التقليدية في PHP.

فكرة حلقة الأحداث

تقدّم PHP غير المتزامنة حلقة أحداث: وهي خيط تنفيذ واحد يسجّل عمليات الإدخال والإخراج بصفتها غير حاجبة، ثم ينتظر في stream_select()/epoll حتى تصبح أيٌّ منها جاهزة، ويفعّل دوال الاستدعاء عند وصول البيانات. يستطيع خيط واحد إدارة آلاف المقابس لأنه لا يبقى خاملاً منتظرًا مقبسًا واحدًا.

<?php
// Conceptual loop: poll many non-blocking streams at once
$streams = openManyNonBlockingSockets();
while ($streams) {
    $read = $streams; $write = $except = [];
    stream_select($read, $write, $except, null); // sleeps until ANY is ready
    foreach ($read as $s) {
        handleReadyStream($s); // runs only the sockets that have data now
    }
}

تعاونية وليست استباقية

تعمل PHP غير المتزامنة بأسلوب تعاوني: تستمر المهام في التنفيذ حتى تتنازل طوعًا عن التحكم عند نقطة إدخال وإخراج. لا توجد جدولة استباقية، لذلك فإن استدعاءً حاجبًا طويلًا أو حلقة ضيقة تستهلك المعالج يوقف حلقة الأحداث بأكملها — فتُحرم جميع المهام الأخرى من التنفيذ. القاعدة الذهبية: لا تستدعوا الدوال الحاجبة أبدًا (sleep، وPDO الحاجب، وfile_get_contents) داخل مهمة تعمل في حلقة الأحداث. استخدموا البدائل غير المتزامنة التي توفرها الحلقة.

ثلاثة أساليب في PHP

توفر PHP الحديثة مجموعة أدوات متعددة الطبقات:

  • Fibers ‏(PHP 8.1، ضمن النواة) — بدائية منخفضة المستوى لإيقاف مكدس الاستدعاءات مؤقتًا ثم استئنافه. وهي لبنة أساسية وليست إطار عمل كاملًا.
  • ReactPHP / Amp — حلقات أحداث في مساحة المستخدم مبنية على التدفقات (وتستخدم الآن Fibers أيضًا) لإجراء عمليات إدخال وإخراج غير حاجبة من دون إضافات.
  • Swoole / OpenSwoole — إضافة بلغة C توفر coroutines وخادمًا عالي الأداء واعتراضات للاستدعاءات الحاجبة.

تحققوا مما هو متاح أثناء التشغيل قبل اختيار الاستراتيجية.

<?php
echo 'Fibers: ' . (class_exists('Fiber') ? 'yes' : 'no'), PHP_EOL;
echo 'Swoole ext: ' . (extension_loaded('swoole') ? 'yes' : 'no'), PHP_EOL;
echo 'parallel ext: ' . (extension_loaded('parallel') ? 'yes' : 'no'), PHP_EOL;
echo 'PHP ' . PHP_VERSION, PHP_EOL;

النماذج المستقبلية للقيم باستخدام الوعود

قبل ظهور Fibers، كانت PHP غير المتزامنة تعرض النتائج المعلّقة على هيئة وعود: وهي عناصر نائبة لقيمة ستُحسم لاحقًا. يمكنكم إرفاق دوال الاستدعاء باستخدام then(). ينجح هذا الأسلوب، لكنه يؤدي إلى سلاسل متداخلة؛ أما Fibers فتتيح للمكتبات إخفاء ذلك خلف await ذي المظهر المتزامن.

<?php
use React\Promise\Promise;

$promise = new Promise(function ($resolve) {
    // resolved later when I/O completes
    $resolve(42);
});
$promise->then(function ($value) {
    echo "got $value\n";
});

التزامن مقابل التوازي

كونوا دقيقين:

  • التزامن — مهام كثيرة قيد التنفيذ، تتناوب على خيط واحد (حلقة الأحداث). وهو مناسب جدًا لعمليات الإدخال والإخراج.
  • التوازي — مهام كثيرة تُنفَّذ في الوقت نفسه على أنوية متعددة (باستخدام العمليات، وإضافة parallel، وعمال المهام في Swoole). وهو ضروري للأعمال التي تستهلك المعالج.

توفر حلقة الأحداث التزامن، لا التوازي. يوضح المقطع أدناه التوازي على مستوى العمليات باستخدام proc_open — إذ يعمل ثلاثة عمال في عمليات منفصلة على مستوى نظام التشغيل في الوقت نفسه.

<?php
$procs = [];
foreach (range(1, 3) as $i) {
    // Each worker is a separate OS process -> real parallelism
    $procs[] = proc_open(
        "php -r 'usleep(500000); echo \"worker $i done\\n\";'",
        [1 => ['pipe', 'w']], $pipes
    );
}
foreach ($procs as $p) { proc_close($p); }
echo "all workers launched in parallel\n";

متى لا تستخدموا الأسلوب غير المتزامن

للأسلوب غير المتزامن تكاليفه: فالعامل طويل العمر يعني أن PHP لن تمسح الحالة بين الطلبات، ولذلك تصبح تسربات الذاكرة وذاكرات التخزين المؤقت الثابتة وتقادم الاتصالات مسؤوليتكم. إذا كان معالج الطلب ينفذ استعلامًا واحدًا إلى قاعدة البيانات ثم يعيد النتيجة، فإن PHP-FPM أبسط وسرعته مماثلة. استخدموا الأسلوب غير المتزامن عندما تحتاجون إلى توزيع عمليات الإدخال والإخراج، أو WebSockets/الاستطلاع الطويل، أو البث، أو خادم دائم التشغيل.

التوازي الحقيقي: ext-parallel والعمليات

بالنسبة إلى توزيع الأعمال التي يهيمن عليها استخدام المعالج، تستطيع PHP تنفيذ توازٍ حقيقي على مستوى نظام التشغيل. تنشئ إضافة parallel خيوط عمال بذاكرة معزولة؛ وبدلًا من ذلك، تنشئ proc_open/pcntl_fork عمليات. وعلى خلاف حلقة الأحداث، تستخدم هذه الآليات عدة أنوية في الوقت نفسه — وهي الأداة المناسبة عندما يكون عنق الزجاجة هو الحساب لا الانتظار.

<?php
// Requires ext-parallel — runs tasks on separate threads/cores
use parallel\Runtime;

$runtime = new Runtime();
$future = $runtime->run(function (): int {
    $sum = 0;
    for ($i = 0; $i < 1_000_000; $i++) $sum += $i; // CPU work on another core
    return $sum;
});
echo $future->value(), PHP_EOL;

تحقق سريع

ماذا يحدث إذا استدعيتم sleep(2) الحاجبة داخل مهمة تعمل في حلقة الأحداث؟

مراجعة

أصبح لديكم الآن نموذج ذهني لتزامن PHP:

  • PHP الافتراضية تزامنية وحاجبة وبلا مشاركة للحالة؛ إذ تتوسع FPM عبر الطلبات، لا داخل الطلب الواحد.
  • يساعد الأسلوب غير المتزامن في الأعمال المقيّدة بعمليات الإدخال والإخراج عبر حلقة أحداث أحادية الخيط تستخدم تدفقات غير حاجبة.
  • النموذج تعاوني — فلا تحجبوا الحلقة أبدًا؛ فالأعمال الطويلة التي تستهلك المعالج تحتاج إلى التوازي لا التزامن.
  • مجموعة أدوات PHP: Fibers (بدائية)، وReactPHP/Amp (حلقات في مساحة المستخدم + وعود)، وSwoole (إضافة coroutines).

الأسئلة الشائعة

هل درس «نموذج التزامن في PHP» مجاني؟

نعم — نص درس «نموذج التزامن في PHP» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة PHP Academy، انتقل إلى CoddyKit PRO. تتضمن دورة PHP Academy 4 دروس في المجموع.

ماذا ستتعلم في «نموذج التزامن في PHP»؟

افهم عمليات الإدخال والإخراج الحاجبة والمواضع التي تفيد فيها العمليات غير المتزامنة. تتمرن على PHP Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ PHP Academy؟

لا تُشترط خبرة سابقة. PHP Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 1 من أصل 4.

كم من الوقت يستغرق درس «نموذج التزامن في PHP»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس PHP Academy هذا؟

نعم. كل درس في PHP Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. نموذج التزامن في PHP
  2. Fibers في PHP 8.1
  3. حلقات الأحداث باستخدام ReactPHP
  4. خوادم عالية الأداء باستخدام Swoole
← العودة إلى PHP Academy