خوادم عالية الأداء باستخدام Swoole
خدّم آلاف الاتصالات باستخدام Swoole القائم على coroutines.
خوادم عالية الأداء باستخدام Swoole درس مجاني في PHP Academy على CoddyKit. هذا هو الدرس 4 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في PHP Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة PHP Academy 4 دروس في المجموع.
ما هو Swoole
Swoole (وشقيقه المتفرع OpenSwoole) هو امتداد C يحوّل PHP إلى بيئة تشغيل عالية الأداء تعتمد على coroutines والأحداث. بدلًا من أن ينشئ PHP-FPM عملية لكل طلب، يهيّئ خادم Swoole تطبيقك مرة واحدة ويبقيه مقيمًا في الذاكرة، ويخدم الطلبات من مجموعة من العمال طويلة العمر المزوّدين بـ coroutines مدمجة. والنتيجة: زيادة هائلة في معدل المعالجة، وتزامن أصلي ضمن طلب واحد.
خادم HTTP المقيم
المثال الكلاسيكي: خادم HTTP كامل داخل نص برمجي. يستمع، ويوجّه كل طلب إلى عامل، ولا يعيد تهيئة إطار العمل من الصفر. لاحظ أن هذا يتطلب ext-swoole — ولا يعمل على PHP CLI المعتادة.
<?php
$server = new Swoole\Http\Server('0.0.0.0', 9501);
$server->set(['worker_num' => 4]);
$server->on('request', function ($request, $response) {
$response->header('Content-Type', 'application/json');
$response->end(json_encode(['hello' => $request->server['request_uri']]));
});
echo "listening on :9501\n";
$server->start();Coroutines بدلًا من Callbacks
أهم ميزة في Swoole هي coroutines: اكتب شيفرة تسلسلية بأسلوب الحجب، بينما تقوم بيئة التشغيل بجدولتها تعاونيًا. تفتح Coroutine\run() سياق coroutine؛ وتطلق go() coroutine جديدة. لكل coroutine مكدسها الخاص، مثل Fiber، لكن Swoole يجدولها تلقائيًا عند نقاط الإدخال والإخراج.
<?php
use Swoole\Coroutine as Co;
Co\run(function () {
go(function () { Co::sleep(1); echo "A done\n"; });
go(function () { Co::sleep(1); echo "B done\n"; });
// Both sleep concurrently -> total ~1s, not 2s
});اعتراض الدوال الحاجبة
السر الذي يجعل coroutines سهلة الاستخدام هو خطافات وقت التشغيل. تعيد Swoole بشفافية كتابة استدعاءات الحجب — PDO وRedis وcurl وsleep وfile_get_contents — إلى إصدارات غير حاجبة ومدركة لـ coroutines. ويؤدي استدعاءك العادي $pdo->query() إلى تعليق coroutine بدلًا من تجميد العامل.
<?php
use Swoole\Runtime;
use Swoole\Coroutine as Co;
Runtime::enableCoroutine(SWOOLE_HOOK_ALL); // hook PDO, curl, sleep, etc.
Co\run(function () {
go(function () { sleep(1); echo "task 1\n"; }); // sleep() is now async!
go(function () { sleep(1); echo "task 2\n"; });
}); // finishes in ~1s because sleep was hookedإدخال وإخراج متزامنان باستخدام WaitGroup
لتوزيع العمل ثم جمع النتائج، توفّر Swoole بنية WaitGroup (مثل sync.WaitGroup في Go). أطلق coroutines، واستدعِ add() لكل مهمة، وdone() عند اكتمالها، ثم wait() لحجب التنفيذ حتى تكتمل جميع المهام — بالتزامن.
<?php
use Swoole\Coroutine as Co;
use Swoole\Coroutine\WaitGroup;
Co\run(function () {
$wg = new WaitGroup();
$results = [];
foreach (['eu', 'us', 'asia'] as $region) {
$wg->add();
go(function () use ($wg, $region, &$results) {
Co::sleep(0.5); // simulated API call
$results[$region] = "ok-$region";
$wg->done();
});
}
$wg->wait(); // all three ran in parallel (~0.5s)
var_dump($results);
});القنوات للتواصل
تنسّق coroutines عبر Channels — وهي طوابير محددة النوع ومحدودة السعة، تعلّق المنتج عند امتلائها والمستهلك عند فراغها. هذه مراسلة بأسلوب CSP، وتتجنب أقفال الحالة المشتركة بالكامل.
<?php
use Swoole\Coroutine as Co;
use Swoole\Coroutine\Channel;
Co\run(function () {
$chan = new Channel(2);
go(function () use ($chan) {
foreach (range(1, 3) as $n) $chan->push($n);
$chan->push(null); // sentinel
});
go(function () use ($chan) {
while (($v = $chan->pop()) !== null) echo "got $v\n";
});
});تجميع الاتصالات
لا ينبغي للخادم المقيم فتح اتصال بقاعدة البيانات لكل طلب. توفّر Swoole تجمعات اتصالات آمنة مع coroutines، بحيث يعيد العمال استخدام مجموعة ثابتة من الاتصالات عبر آلاف coroutines المتزامنة، مما يلغي تبدّل الاتصالات المستمر.
<?php
use Swoole\Database\PDOConfig;
use Swoole\Database\PDOPool;
use Swoole\Coroutine as Co;
Co\run(function () {
$pool = new PDOPool((new PDOConfig())
->withHost('127.0.0.1')->withDbname('app')
->withUsername('u')->withPassword('p'), 8);
go(function () use ($pool) {
$pdo = $pool->get(); // borrow
$row = $pdo->query('SELECT NOW()')->fetch();
$pool->put($pdo); // return to pool
var_dump($row);
});
});تسرّب الحالة: فخ الذاكرة المقيمة
لأن العملية تستمر عبر الطلبات، تبقى الحالة العامة والثابتة موجودة. فقد يؤدي نمو ذاكرة تخزين مؤقتة ثابتة بلا حدود، أو احتفاظ singleton ببيانات خاصة بطلب، أو تسرّب معاملة لقاعدة البيانات، إلى إفساد الطلبات اللاحقة واستنزاف الذاكرة. القواعد: تجنّب تخزين بيانات خاصة بالطلب في المتغيرات الثابتة أو singleton، وأعد ضبط سياق كل طلب، واضبط max_request كي يُعاد تدوير العمال دوريًا.
<?php
$server = new Swoole\Http\Server('0.0.0.0', 9501);
$server->set([
'worker_num' => 8,
'max_request' => 10000, // recycle a worker after N requests to bound leaks
]);
// Never store $request data in a static property between requests!السياق المحلي لـ coroutine
بما أن عاملًا واحدًا ي interleave بين العديد من coroutines، لا يمكنك استخدام المتغيرات الثابتة العادية للبيانات الخاصة بالطلب. تمنح Swoole كل coroutine سياقًا (Coroutine::getContext()) — وهو كائن يستمر طوال مدة coroutine، ومناسب تمامًا للمستخدم الحالي أو معرّف الطلب أو مقبض المعاملة.
<?php
use Swoole\Coroutine as Co;
Co\run(function () {
go(function () {
$ctx = Co::getContext();
$ctx['request_id'] = 'req-123';
// ... deep call chain can read Co::getContext()['request_id']
echo Co::getContext()['request_id'], PHP_EOL;
});
});نموذج العمليات وعمال المهام
تشغّل Swoole عملية رئيسية (تدير خيوط حلقة الأحداث)، ومديرًا (ينشئ العمال ويراقبهم)، وعمليات عاملة (تشغّل معالجات الطلبات الخاصة بك وcoroutines)، وعمال مهام اختياريين للمهام الثقيلة أو الحاجبة أو المقيدة بالمعالج، والتي تُسند إليهم عبر $server->task(). استخدم عمال المهام لمعالجة الصور أو الأعمال الطويلة التي تعتمد على المعالج، حتى لا تعرقل coroutines الخاصة بالطلبات — فتحصل على التزامن والتوازي معًا.
التأجيل والمؤقتات
تتيح لك Swoole جدولة العمل بعد انتهاء coroutine الحالية باستخدام Coroutine::defer() — وهذا مثالي لتحرير الموارد المجمّعة بشكل موثوق حتى عند طرح استثناء. وتشغّل المؤقتات على مستوى الخادم (Timer::tick) مهام دورية مثل تحديث ذاكرة التخزين المؤقت داخل العامل، من دون cron خارجي.
<?php
use Swoole\Coroutine as Co;
Co\run(function () {
go(function () {
$conn = 'borrowed-connection';
Co::defer(function () use ($conn) {
echo "released $conn\n"; // runs when coroutine exits, even on error
});
echo "using $conn\n";
});
});اختبار سريع
لماذا يجب تجنّب تخزين بيانات الطلب في الخصائص الثابتة في خادم Swoole؟
خلاصة
تحوّل Swoole PHP إلى خادم مقيم تديره coroutines:
- يُهيّأ التطبيق مرة واحدة؛ وتخدم مجموعة العمال الطلبات باستخدام coroutines مدمجة (
Co\run/go()). - تجعل خطافات وقت التشغيل عمليات PDO وcurl وsleep العادية غير حاجبة؛ بينما تنسّق WaitGroup وChannels العمل المتزامن.
- تعيد تجمعات الاتصالات استخدام اتصالات قاعدة البيانات عبر coroutines.
- تعني الذاكرة المقيمة ضرورة تجنّب تسرّب الحالة: استخدم
Coroutine::getContext()للبيانات الخاصة بالطلب، واضبطmax_request، وأسند الأعمال الثقيلة إلى عمال المهام.
تعلم PHP مع معلم ذكاء اصطناعي — مجانًا
اكتب وقم بتشغيل أكوادك الفعلية في المتصفح، واحصل على مساعدة فورية من معلم ذكاء اصطناعي متاح 24/7، واستمر من حيث توقفت على الويب أو في التطبيق.
- الدورات
- 49
- الدروس
- 195
الأسئلة الشائعة
هل درس «خوادم عالية الأداء باستخدام Swoole» مجاني؟
نعم — نص درس «خوادم عالية الأداء باستخدام Swoole» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة PHP Academy، انتقل إلى CoddyKit PRO. تتضمن دورة PHP Academy 4 دروس في المجموع.
ماذا ستتعلم في «خوادم عالية الأداء باستخدام Swoole»؟
خدّم آلاف الاتصالات باستخدام Swoole القائم على coroutines. تتمرن على PHP Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ PHP Academy؟
لا تُشترط خبرة سابقة. PHP Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 4 من أصل 4.
كم من الوقت يستغرق درس «خوادم عالية الأداء باستخدام Swoole»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس PHP Academy هذا؟
نعم. كل درس في PHP Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- نموذج التزامن في PHP
- Fibers في PHP 8.1
- حلقات الأحداث باستخدام ReactPHP
- خوادم عالية الأداء باستخدام Swoole