التزامن وتعدد الخيوط في PHP: دليل عملي

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة
```html

مقدمة: لماذا يحتاج PHP إلى التزامن

تُعتبر PHP تقليديًا لغة متزامنة (synchronous)، حيث تتم معالجة كل طلب بشكل تسلسلي. ومع ذلك، تتطلب تطبيقات الويب الحديثة تنفيذ مهام متعددة في وقت واحد: معالجة قوائم الانتظار، العمل مع API، معالجة الصور، تحليل البيانات. يسمح التزامن (Concurrency) وتعدد الخيوط (Multithreading) في PHP بحل هذه المهام، مما يزيد من أداء واستجابة التطبيقات.

في هذه المقالة، سنستعرض الأساليب الرئيسية: تعدد الخيوط عبر pthreads، والعمليات المتوازية عبر pcntl_fork، والبرمجة غير المتزامنة باستخدام ReactPHP، و Fibers الحديثة في PHP 8.1+. لكل طريقة نقاط قوتها وقيودها، والتي سنناقشها من خلال أمثلة عملية.



النهج 1: تعدد الخيوط باستخدام إضافة pthreads

pthreads هي إضافة للعمل مع الخيوط (threads) في PHP. وهي متاحة فقط لإصدار CLI وتتطلب بناءً مع العلم --enable-maintainer-zts. تشارك الخيوط الذاكرة، مما يسمح بتبادل البيانات بكفاءة، ولكنه يتطلب الحذر مع الأقفال (locks).

التثبيت والإعداد

# التثبيت عبر peclpecl install pthreads

# التحقق في php.iniextension=pthreads.so

مثال: معالجة مصفوفة بالتوازي

<?phpclass WorkerThread extends Thread {    private $data;    private $result;

public function __construct($data) { $this->data = $data; }

public function run() { // محاكاة عملية ثقيلة $this->result = array_map(function($item) { sleep(1); // 1 ثانية لكل عنصر return $item * 2; }, $this->data); }

public function getResult() { return $this->result; }}

// إنشاء 5 خيوط$threads = [];$dataChunks = array_chunk(range(1, 100), 20);

foreach ($dataChunks as $chunk) { $thread = new WorkerThread($chunk); $thread->start(); $threads[] = $thread;}

// جمع النتائج$finalResult = [];foreach ($threads as $thread) { $thread->join(); $finalResult = array_merge($finalResult, $thread->getResult());}

echo "تمت معالجة " . count($finalResult) . " عنصر في حوالي 5 ثوانٍ بدلاً من 100.";

هام: pthreads لا يعمل في بيئة الويب (Apache/Nginx + mod_php). استخدمه فقط لسكريبتات CLI، والعمال (workers)، والخدمات الخلفية (daemons).



النهج 2: العمليات المتوازية عبر pcntl_fork

الدالة pcntl_fork() تنشئ عملية فرعية (child process)، وتنسخ السكريبت الحالي. العمليات معزولة في الذاكرة، مما يجعلها أكثر أمانًا من الخيوط، ولكن التواصل بين العمليات (IPC) يتطلب آليات إضافية: قوائم انتظار الرسائل، الذاكرة المشتركة، أو المقابس (sockets).

مثال: تحميل URLs بالتوازي

<?php$urls = [    'https://api.example.com/data1',    'https://api.example.com/data2',    'https://api.example.com/data3',];

$pids = [];foreach ($urls as $url) { $pid = pcntl_fork(); if ($pid == -1) { die("خطأ في fork"); } elseif ($pid == 0) { // العملية الفرعية $content = file_get_contents($url); file_put_contents('/tmp/' . md5($url) . '.json', $content); exit(0); // من المهم إنهاء العملية الفرعية } else { $pids[] = $pid; }}

// انتظار انتهاء جميع العمليات الفرعيةforeach ($pids as $pid) { pcntl_waitpid($pid, $status);}

echo "تم تحميل جميع URLs بالتوازي.";

القيود:

  • لا يعمل مع خادم الويب (CLI فقط).
  • تستهلك كل عملية ذاكرة العملية الأم.
  • من الصعب مزامنة الوصول إلى الموارد المشتركة.


النهج 3: البرمجة غير المتزامنة مع ReactPHP

ReactPHP هي مكتبة للبرمجة الموجهة بالأحداث (event-driven programming ```

المدونات

توصيات الكتب