Internet Windows Android

Programare multi-threaded în PHP folosind Pthreads Translation. Alegerea unei versiuni PHP pentru Windows Anemic discuții php

Se pare că dezvoltatorii PHP folosesc rar concurența. Nu voi vorbi despre simplitatea codului sincron, programarea cu un singur thread este, desigur, mai simplă și mai clară, dar uneori o mică utilizare a paralelismului poate aduce o creștere vizibilă a performanței.

În acest articol, vom arunca o privire asupra modului în care poate fi realizat multithreading în PHP folosind extensia pthreads. Acest lucru va necesita instalarea versiunii ZTS (Zend Thread Safety) a PHP 7.x, împreună cu extensia pthreads v3 instalată. (La momentul scrierii, în PHP 7.1, utilizatorii vor trebui să instaleze din ramura principală din depozitul pthreads - vezi extensia terță parte.)

O mică precizare: pthreads v2 este destinat PHP 5.x și nu mai este acceptat, pthreads v3 este pentru PHP 7.x și este în curs de dezvoltare.

După o astfel de digresiune, să trecem direct la subiect!

Prelucrarea sarcinilor unice

Uneori doriți să procesați sarcini unice într-un mod cu mai multe fire (de exemplu, executând unele sarcini legate de I/O). În astfel de cazuri, puteți utiliza clasa Thread pentru a crea un fir nou și pentru a rula unele procesări pe un fir separat.

De exemplu:

$task = noua clasă extinde Thread ( private $response; public function run() ( $content = file_get_contents("http://google.com"); preg_match("~ (.+)~", $conținut, $potriviri); $this->response = $match; ) ); $task->start() && $task->join(); var_dump($task->response); // șir (6) „Google”

Aici metoda de rulare este procesarea noastră, care va fi executată într-un fir nou. Când este apelat Thread::start, este generat un nou thread și este apelată metoda de rulare. Apoi unim firul copil înapoi la firul principal apelând Thread::join , care se va bloca până când firul copil se va termina de execuție. Acest lucru asigură că sarcina se termină de executat înainte de a încerca să tipărim rezultatul (care este stocat în $task->response).

Este posibil să nu fie de dorit să poluăm o clasă cu responsabilități suplimentare asociate cu logica fluxului (inclusiv responsabilitatea definirii unei metode de rulare). Putem distinge astfel de clase prin moștenirea lor din clasa Threaded. Apoi pot fi rulate într-un alt thread:

Class Task extinde Threaded ( public $response; funcția publică someWork() ( $content = file_get_contents("http://google.com"); preg_match("~ (.+) ~", $content, $match); $ this->response = $potrivește ) ) $sarcină = sarcină nouă; $thread = clasă nouă($sarcină) extinde Thread (privată $sarcină; funcția publică __construct(Thread $sarcină) ( $aceasta->sarcină = $sarcină; ) funcția publică run() ( $aceasta->sarcină->someWork( ); )); $thread->start() && $thread->join(); var_dump($sarcină->răspuns);

Orice clasă care trebuie rulată într-un fir separat trebuie sa moștenește din clasa Threaded. Acest lucru se datorează faptului că oferă capabilitățile necesare pentru a efectua procesări pe diferite fire, precum și securitate implicită și interfețe utile (cum ar fi sincronizarea resurselor).

Să aruncăm o privire la ierarhia claselor oferită de extensia pthreads:

Filet (implementează Traversable, Collectable) Thread Worker Pool Volatile

Am acoperit și am învățat deja elementele de bază ale claselor Thread și Threaded, acum să aruncăm o privire la celelalte trei (Worker, Volatile și Pool).

Reutilizarea Firelor

Începerea unui fir nou pentru fiecare sarcină care trebuie paralelizată este destul de costisitoare. Acest lucru se datorează faptului că o arhitectură comun-nimic trebuie implementată în pthreads pentru a realiza multithreading în PHP. Ceea ce înseamnă că întregul context de execuție al instanței curente a interpretului PHP (inclusiv fiecare clasă, interfață, trăsătură și funcție) trebuie copiat pentru fiecare fir creat. Deoarece acest lucru are un impact vizibil asupra performanței, fluxul ar trebui să fie întotdeauna reutilizat ori de câte ori este posibil. Threadurile pot fi reutilizate în două moduri: folosind Workers sau folosind Pools.

Clasa Worker este folosită pentru a efectua o serie de sarcini sincron în cadrul unui alt fir. Acest lucru se face prin crearea unei noi instanțe Worker (care creează un fir nou), apoi împingând sarcini în stiva acelui fir separat (folosind Worker::stack).

Iată un mic exemplu:

Class Task se extinde Threaded ( private $valoare; funcția publică __construct(int $i) ( $this->value = $i; ) public function run() ( usleep(250000); echo "Task: ($this->value) \n"; ) ) $lucrător = nou Lucrător(); $lucrător->start(); for ($i = 0; $i stack(new Task($i)); ) while ($worker->collect()); $worker->shutdown();

În exemplul de mai sus, 15 sarcini pentru un nou obiect $worker sunt împinse în stivă prin metoda Worker::stack și apoi sunt procesate în ordinea în care au fost împinse. Metoda Worker::collect, așa cum se arată mai sus, este utilizată pentru a curăța sarcinile de îndată ce se termină de executat. Cu ea, într-o buclă while, blocăm firul principal până când toate sarcinile de pe stivă sunt finalizate și șterse - înainte de a apela Worker::shutdown . Terminarea timpurie a unui lucrător (adică în timp ce încă mai sunt sarcini care trebuie finalizate) va bloca în continuare firul principal până când toate sarcinile își vor finaliza execuția, doar că sarcinile nu vor fi colectate de gunoi (ceea ce implică pierderi de memorie).

Clasa Worker oferă câteva alte metode legate de stiva sa de sarcini, inclusiv Worker::unstack pentru eliminarea ultimei sarcini stivuite și Worker::getStacked pentru obținerea numărului de sarcini din stiva de execuție. Stiva unui lucrător conține doar sarcinile care trebuie executate. Odată ce o sarcină din stivă a fost finalizată, aceasta este eliminată și plasată pe o stivă separată (internă) pentru colectarea gunoiului (folosind metoda Worker::collect).

O altă modalitate de a reutiliza un fir de execuție în mai multe sarcini este utilizarea unui pool de fire de execuție (prin clasa Pool). Un grup de fire de execuție folosește un grup de lucrători pentru a permite executarea sarcinilor. simultan, în care factorul de concurență (numărul de fire de execuție cu care operează) este setat la crearea grupului.

Să adaptăm exemplul de mai sus pentru a folosi un grup de lucrători:

Class Task se extinde Threaded ( private $valoare; funcția publică __construct(int $i) ( $this->value = $i; ) public function run() ( usleep(250000); echo "Task: ($this->value) \n"; ) ) $pool = pool nou(4); for ($i = 0; $i submit(new Task($i)); ) while ($pool->collect()); $pool->shutdown();

Există câteva diferențe notabile atunci când utilizați o piscină, spre deosebire de un lucrător. În primul rând, pool-ul nu trebuie să fie pornit manual, acesta începe să execute sarcini imediat ce acestea devin disponibile. În al doilea rând, noi trimite sarcini la piscină, nu pune-le pe un teanc. În plus, clasa Pool nu moștenește din Threaded și, prin urmare, nu poate fi transmisă altor fire (spre deosebire de Worker).

Ca o bună practică, lucrătorii și piscinele ar trebui să-și curețe întotdeauna sarcinile de îndată ce le finalizează și apoi să le încheie manual ei înșiși. Firele create folosind clasa Thread trebuie, de asemenea, atașate firului părinte.

pthreads și (im)mutabilitatea

Ultima clasă pe care o vom atinge este Volatile, o nouă adăugare la pthreads v3. Imuabilitatea a devenit un concept important în pthreads, deoarece fără ea, performanța suferă semnificativ. Prin urmare, în mod implicit, proprietățile claselor Threaded care sunt ele însele obiecte Threaded sunt acum imuabile și, prin urmare, nu pot fi suprascrise după atribuirea lor inițială. Mutabilitatea explicită pentru astfel de proprietăți este în prezent preferată și poate fi încă obținută folosind noua clasă Volatile.

Să ne uităm la un exemplu care va demonstra noile restricții de imuabilitate:

Class Task extinde Threaded // o clasă Threaded (funcția publică __construct() ( $this->data = new Threaded(); // $this->data nu poate fi suprascris, deoarece este o proprietate Threaded a unei clase Threaded) ) $task = new class(new Task()) extinde Thread ( // o clasă Threaded, deoarece Thread extinde Thread funcția publică __construct($tm) ( $this->threadedMember = $tm; var_dump($this->threadedMember-> data); // obiect(Threaded)#3 (0) () $this->threadedMember = new StdClass( // invalid, deoarece proprietatea este un membru Threaded al unei clase Threaded ) );

Proprietățile filetate ale claselor Volatile, pe de altă parte, sunt mutabile:

Class Task extinde Volatile (funcția publică __construct() ( $this->data = new Threaded(); $this->data = new StdClass(); // valid, deoarece suntem într-o clasă volatilă ) ) $task = new class(new Task()) extinde Thread (funcția publică __construct($vm) ( $this->volatileMember = $vm; var_dump($this->volatileMember->data); // obiect(stdClass)#4 (0) () // încă invalid, deoarece Volatile extinde Threaded, deci proprietatea este încă un membru Threaded al clasei Threaded $this->volatileMember = new StdClass() );

Putem vedea că clasa Volatile suprascrie imuabilitatea impusă de clasa părinte Threaded pentru a oferi posibilitatea de a schimba proprietățile Threaded (precum și unset()).

Există un alt subiect de discuție pentru a acoperi tema variabilității și a clasei Volatile - matrice. În pthreads, matricele sunt turnate automat în obiecte Volatile atunci când sunt atribuite unei proprietăți a clasei Threaded. Acest lucru se datorează faptului că pur și simplu nu este sigur să manipulați o serie de mai multe contexte PHP.

Să ne uităm din nou la un exemplu pentru a înțelege mai bine unele lucruri:

$matrice = ; $sarcină = clasă nouă($array) extinde Thread ( private $date; public function __construct(array $array) ( $this->data = $array; ) public function run() ( $this->data = 4; $ this->data = 5 print_r($this->data) ); $sarcină->start() && $sarcină->join(); /* Ieșire: obiect volatil ( => 1 => 2 => 3 => 4 => 5) */

Vedem că obiectele volatile pot fi tratate ca și cum ar fi matrice, deoarece acceptă operații cu matrice, cum ar fi (așa cum se arată mai sus) operatorul subset(). Cu toate acestea, clasele Volatile nu acceptă funcții de bază ale matricei, cum ar fi array_pop și array_shift. În schimb, clasa Threaded ne oferă astfel de operații ca metode încorporate.

Ca demonstrație:

$date = clasă nouă se extinde Volatil ( public $a = 1; public $b = 2; public $c = 3; ); var_dump($date); var_dump($date->pop()); var_dump($date->shift()); var_dump($date); /* Ieșire: obiect(clasă@anonim)#1 (3) ( ["a"]=> int(1) ["b"]=> int(2) ["c"]=> int(3) ) int(3) int(1) obiect(clasa@anonim)#1 (1) ( ["b"] => int(2) ) */

Alte operațiuni acceptate includ Threaded::chunk și Threaded::merge .

Sincronizare

În ultima secțiune a acestui articol, ne vom uita la sincronizarea în pthreads. Sincronizarea este o metodă care vă permite să controlați accesul la resursele partajate.

De exemplu, să implementăm un contor simplu:

$counter = noua clasa extinde Thread ( public $i = 0; public function run() ( for ($i = 0; $i i; ) ) ); $contor->start(); pentru ($i = 0; $i i; ) $counter->join(); var_dump($contor->i); // va tipări un număr de la 10 la 20

Fără utilizarea sincronizării, ieșirea nu este deterministă. Mai multe fire de execuție scriu pe aceeași variabilă fără acces controlat, ceea ce înseamnă că actualizările se vor pierde.

Să reparăm acest lucru, astfel încât să obținem rezultatul corect de 20 prin adăugarea de sincronizare:

$counter = noua clasa extinde Thread ( public $i = 0; public function run() ( $this->synchronized(function () ( for ($i = 0; $i i; ) )); ) ); $contor->start(); $contor->sincronizat(funcție ($contor) ( pentru ($i = 0; $i i; ) ), $contor); $counter->join(); var_dump($contor->i); // int(20)

Blocurile de cod sincronizate pot comunica, de asemenea, între ele folosind metodele Threaded::wait și Threaded::notify (sau Threaded::notifyAll).

Iată un increment alternativ în două bucle while sincronizate:

$counter = noua clasa extinde Thread ( public $cond = 1; public function run() ( $this->synchronized(function ()) (pentru ($i = 0; $i notify();); if ($this->cond === 1) ( $this->cond = 2; $this->wait(); ) ) )); $contor->start(); $contor->sincronizat(funcție ($contor) ( if ($contor->cond !== 2) ( $contor->wait(); // așteptați ca celălalt să pornească primul ) pentru ($i = 10; $i notify(); if ($counter->cond === 2) ( $counter->cond = 1; $counter->wait(); ) ) ), $counter); $counter->join(); /* Ieșire: int(0) int(10) int(1) int(11) int(2) int(12) int(3) int(13) int(4) int(14) int(5) int( 15) int(6) int(16) int(7) int(17) int(8) int(18) int(9) int(19) */

Este posibil să observați condiții suplimentare care au fost plasate în jurul apelului către Threaded::wait . Aceste condiții sunt critice deoarece permit reluarea apelului sincronizat atunci când a primit o notificare și condiția specificată este adevărată. Acest lucru este important deoarece notificările pot veni din alte locuri decât atunci când Threaded::notify este apelat. Astfel, dacă apelurile la metoda Threaded::wait nu au fost incluse în condiții, vom executa apeluri de trezire false, ceea ce va duce la un comportament imprevizibil al codului.

Concluzie

Am analizat cele cinci clase ale pachetului pthreads (Threaded, Thread, Worker, Volatile și Pool) și cum este utilizată fiecare clasă. De asemenea, am aruncat o privire asupra noului concept de imuabilitate în pthreads și am oferit o scurtă prezentare generală a capabilităților de sincronizare acceptate. Cu aceste elemente de bază, acum putem începe să ne uităm la modul în care pthread-urile pot fi utilizate în cazurile din lumea reală! Acesta va fi subiectul următoarei noastre postări.

Dacă ești interesat de traducerea următoarei postări, anunță-mă: comentează pe rețelele de socializare. rețele, votează pozitiv și distribuie postarea colegilor și prietenilor.

Uneori devine necesar să se efectueze mai multe acțiuni simultan, de exemplu, verificarea modificărilor într-un tabel al bazei de date și efectuarea modificărilor la altul. Mai mult, dacă una dintre operații (de exemplu, verificarea modificărilor) durează mult, este evident că execuția secvențială nu va asigura echilibrarea resurselor.

Pentru a rezolva acest tip de problemă, programarea folosește multithreading - fiecare operație este plasată într-un fir separat cu o cantitate alocată de resurse și funcționează în cadrul acestuia. Cu această abordare, toate sarcinile vor fi îndeplinite separat și independent.

Deși PHP nu acceptă multithreading, există mai multe metode de emulare, care vor fi discutate mai jos.

1. Rularea mai multor copii ale scriptului - o copie per operație

//woman.php if (!isset($_GET["thread"])) ( system("wget ​​​​http://localhost/woman.php?thread=make_me_happy"); system("wget ​​​​http: //localhost/ woman.php?thread=make_me_rich"); ) elseif ($_GET["thread"] == "make_me_happy") ( make_her_happy(); ) elseif ($_GET["thread"] == "make_me_rich" ) ( găsește_altul_unul( ; )

Când executăm acest script fără parametri, rulează automat două copii ale lui însuși, cu ID-uri de operație ("thread=make_me_happy" și "thread=make_me_rich"), care inițiază execuția funcțiilor necesare.

Astfel obținem rezultatul dorit - două operații sunt efectuate simultan - dar acesta, desigur, nu este multithreading, ci pur și simplu o cârjă pentru îndeplinirea sarcinilor simultan.

2. Calea Jedi - folosind extensia PCNTL

PCNTL este o extensie care vă permite să lucrați pe deplin cu procesele. Pe lângă management, acceptă trimiterea de mesaje, verificarea stării și stabilirea priorităților. Iată cum arată scriptul anterior folosind PCNTL:

$pid = pcntl_fork(); if ($pid == 0) ( make_her_happy(); ) elseif ($pid > 0) ( $pid2 = pcntl_fork(); if ($pid2 == 0) ( find_nother_one(); ) )

Pare destul de confuz, hai să trecem prin el rând cu rând.

În prima linie, „furcăm” procesul curent (furcația este copierea unui proces, păstrând în același timp valorile tuturor variabilelor), împărțindu-l în două procese (curent și copil) care rulează în paralel.

Pentru a înțelege dacă ne aflăm în prezent într-un proces copil sau mamă, funcția pcntl_fork returnează 0 pentru copil și ID-ul procesului pentru mamă. Prin urmare, în a doua linie, ne uităm la $pid, dacă este zero, atunci suntem în procesul copil - executăm funcția, în caz contrar, suntem în mamă (linia 4), apoi creăm un alt proces și în mod similar, efectuați sarcina.

Procesul de executare a scriptului:

Astfel, scriptul creează încă 2 procese copil, care sunt copiile sale și conțin aceleași variabile cu valori similare. Și folosind identificatorul returnat de funcția pcntl_fork, aflăm în ce fir ne aflăm în prezent și efectuăm acțiunile necesare.

Atenţie! Acest articol este iremediabil depășit sau este acum evaluat de autor ca neavând niciun beneficiu informațional.

Frumusețea codului open-source este deschiderea lui :)) Adică. dacă aveți inteligență/timp/dorință, vă puteți da seama exact cum funcționează programul. Dezavantajul unui astfel de cod este dificultatea de a obține pachetele compilate necesare. De exemplu, PHP poate fi descărcat ca surse pentru sistemele Nix cu compilare/asamblare ulterioară. Totul este deja asamblat pentru Windows, dar există o mulțime de pachete binare gata făcute! Opțiuni cu „ fire safe/non thread safe", VC6/VC9și diferite versiuni ale PHP în sine. Articolul a fost creat pentru a clarifica situația. Se bazează pe diferite surse, parțial pe traducerea din engleză. Totul pentru ca data viitoare să nu mai fiu nevoit să-mi dau seama din nou - „ce rost are!?”

Necesar versiunea PHP depinde de versiunea serverului web pe care va fi utilizat. De exemplu, Apache 1.3.x funcționează cu versiunea PHP 3.0.x, Apache 2.x funcționează cu versiunea PHP 4.0 și mai mare. Dar aceasta nu este o astfel de problemă, concentrează-te pe versiuni mai noi stabile și pe ceea ce are hosterul.

Ce fel de postscripte VC6, VC9, VC11? Sursele PHP pentru Windows sunt compilate în Visual Studio. VC9 este obținut atunci când este compilat în VS 2008, VC11 - Visual Studio 2012. În consecință, pentru ca toate acestea să funcționeze pentru dvs., bibliotecile trebuie să fie instalate pe computer Visual C++ redistribuibil pentru Visual Studio anul corespunzător. Câteva clarificări pe această temă.

În plus, dacă serverul dvs. web este un Apache vechi de pe apache.org, atunci trebuie să descărcați versiunea VC6 de PHP, pentru compilare a cărei Visual Studio 6 a fost folosit dacă PHP va funcționa pentru IIS sau împreună cu un Apache mai nou , atunci poti colecta ceva mai modern ;)

Pentru mine, principalul obstacol în alegere este hosterul. Acum există o versiune stabilă a PHP 5.5.4, dar încă mai are 5.2.17!

Acum partea interesantă: " fir de siguranta sau fără fir sigur?"
Traducere gratuită a articolului (Dominic Ryan, 27.09.2007)

Nu am văzut niciodată o astfel de engleză stricata:((Voiam să traduc rapid articolul, dar îmi este greu să înțeleg ce a scris autorul. Tranzițiile constante între „ce-e-aia” și propozițiile complexe fac în general Moscova să iasă în evidență. Traducerea în rusă este la fel complicat de faptul că nu am suficiente cunoștințe și imaginație cu privire la cum să numesc corect ceva în rusă, care de obicei este scris doar în engleză%). De exemplu, nu am văzut niciodată conceptul tehnic de „arhitectură multiproces” în Rusă, dar perla mea este „nesigură pentru curgere” este în general o chestiune de bun simț. În general, vă voi spune ce sa întâmplat.

Diferență între fir de sigurantaȘi fără fir sigur Pachete binare PHP

De când PHP a apărut pentru prima dată pe Windows pe 20 octombrie 2000 cu PHP 3.0.17, pachetele sale binare au fost întotdeauna construite ca sigur pentru fir (TS). Motivul este următorul: Windows utilizează o arhitectură cu mai multe fire, iar sistemele Nix acceptă o arhitectură cu mai multe procese. Dacă PHP a fost compilat ca o aplicație CGI cu mai multe procese în loc de una cu mai multe fire, atunci folosirea lui ca modul CGI sub Windows pe un server IIS duce la încetiniri severe și la utilizarea procesorului. Pe de altă parte, puteți conecta PHP la IIS ca modul ISAPI ( este necesară construcția cu mai multe fire- aprox. traducător). Apoi apare o altă problemă: unele extensii PHP populare sunt proiectate cu Unix/Linux în minte, de exemplu. cu o arhitectură multi-proces, ceea ce duce la blocarea PHP conectat la IIS ca modul ISAPI. Acea. Crearea CGI este cel mai stabil mediu pentru PHP pe IIS, cu principalul dezavantaj că este teribil de lent. Trebuie să încărcăm și să descarcăm întregul mediu PHP din memorie de fiecare dată când există o solicitare.

La acea vreme, existau mai multe opțiuni pentru a îmbunătăți performanța PHP pe IIS. Primul este de a folosi opcode cache cu programe precum eAccelerator, care stochează scripturi PHP într-o stare parțial compilată pe disc și/sau în memorie. Această abordare reduce semnificativ timpul de execuție a scriptului. O altă opțiune a fost configurarea IIS pentru a utiliza PHP în modul FastCGI. În acest caz, procesul PHP nu s-a închis după finalizare, ci a primit o nouă sarcină cu următoarea solicitare PHP. În plus, a fost posibilă rularea mai multor procese PHP în același timp, accelerând semnificativ procesarea cererilor, ceea ce a fost un bonus al modului PHP CGI. Cu toate acestea, este posibil să fi existat probleme minore de compatibilitate cu extensiile PHP. Acesta este încă cel mai rapid mod de a utiliza PHP și este configurat pentru a face IIS Aid PHP Installer.

Binare colectate în modul thread-unsafe (non thread safe, NTS), vă permit să configurați IIS (și alte servere web pe Windows) pentru a utiliza PHP ca interfață CGI standard cu o creștere puternică a performanței, deoarece în acest caz (într-o astfel de construcție), procesul PHP nu trebuie să aștepte ca firele să se sincronizeze. Când se compară performanța pachetelor binare PHP „thread safe” și „non thread safe” pe IIS ca interfață CGI standard, creșterea performanței este de până la 40%, dar încă nu este la fel de rapidă ca utilizarea unui opcode în metoda FastCGI . Și cea mai mare problemă este că nu puteți utiliza în mod fiabil binarele nesigure pentru fire împreună cu cele sigure pentru fire. Aceasta înseamnă că nu puteți utiliza sisteme de stocare în cache opcode precum eAccelerator într-un mediu PHP creat de pachete binare nesigure pentru fire (o declarație care este corectă la momentul scrierii).

Dacă PHP nesigur pentru fire nu poate fi configurat la aceeași viteză ca un mediu sigur pentru fire, atunci de ce este necesar într-o astfel de versiune? Să revenim la evoluțiile FastCGI și Microsoft în acest domeniu în ultimii câțiva ani. Codificatorii mici și soft au creat propria lor versiune de FastCGI, care vă permite să configurați binare PHP nesigure pentru fire în modul FastCGI, ceea ce aduce performanță la viteza luminii :)

Din articol am ajuns la concluzia că frânele sunt respectate doar atunci când sunt folosite cu serverul web IIS. În orice caz, nu am văzut nimic stupid sub Windows+Apache. De asemenea, spune că puteți overclocka ansamblul NTS orice server web, dar nu îmi pot imagina o astfel de configurație Apache.

Am încercat recent pthreads și am fost plăcut surprins - este o extensie care adaugă capacitatea de a lucra cu mai multe fire reale în PHP. Fără emulare, fără magie, fără falsuri - totul este real.



Mă gândesc la această problemă. Există o serie de sarcini care trebuie finalizate rapid. PHP are alte instrumente pentru rezolvarea acestei probleme, ele nu sunt menționate aici, articolul este despre pthreads.



Ce sunt pthread-urile

Asta e tot! Ei bine, aproape totul. De fapt, există ceva care poate supăra un cititor curios. Nimic din acestea nu funcționează pe PHP standard compilat cu opțiuni implicite. Pentru a vă bucura de multithreading, trebuie să aveți ZTS (Zend Thread Safety) activat în PHP.

Configurare PHP

Apoi, PHP cu ZTS. Nu vă deranjează marea diferență de timp de execuție față de PHP fără ZTS (37.65 vs 265.05 secunde), nu încercam să generalizez configurarea PHP. În cazul fără ZTS, am XDebug activat, de exemplu.


După cum puteți vedea, atunci când utilizați 2 fire, viteza de execuție a programului este de aproximativ 1,5 ori mai mare decât în ​​cazul codului liniar. Când utilizați 4 fire - de 3 ori.


Puteți observa că, deși procesorul este cu 8 nuclee, timpul de execuție al programului a rămas aproape neschimbat dacă s-au folosit mai mult de 4 fire. Se pare că acest lucru se datorează faptului că procesorul meu are 4 nuclee fizice Pentru claritate, am înfățișat placa sub formă de diagramă.


rezumat

În PHP, este posibil să lucrați destul de elegant cu multithreading folosind extensia pthreads. Acest lucru oferă o creștere vizibilă a productivității.

Etichete: Adăugați etichete