Tulburări de panică. Tulburări de panică Procesarea sarcinilor unice


02.10.2011, 21:27

Pentru că a bătut un tip și i-a atârnat tricoul de un copac. Și ea l-a urmărit pe tip idiot singură pentru câțiva kilometri și când a căzut a început să se urineze pe el. Dar au meritat.

Într-o companie mare, am deranjat o fată și am spus că iubitul ei a cumpărat-o la o reducere și a mâncat banane și a pus cojile pe poale tuturor în microbuz și, de asemenea, organizez constant spectacole lesbiene în baruri, odată ce m-am uitat sub fuste. ale chelnerițelor dintr-un club VIP și au dat comentarii, dar în general sunt prost beat, uit imediat că îmi place oamenii să spună dacă te trezești și ți-e rușine, dar nu-ți amintesc de ce anume despre mine

După ultima beție m-am săturat:
1. a țipat de la balcon către tipul „suge-mă”
2. a mâncat o țigară
3. a aruncat cu mere
4. l-a sunat pe tip și i-a spus că nu-i voi face sex într-un mod nepoliticos
5. tauri înecați în suc de grepfrut
6. a sunat-o pe mama și mi-a spus că sunt treaz
7. L-am rugat pe iubitul prietenului meu să ne aducă niște vin.
8. Am urinat pe lângă toaletă, deoarece erau 2 - am ales-o pe cea greșită și apoi am căzut
9. a căzut din baie

Am alergat o dată prin apartament cu un cuțit după soțul meu, deși am băut câteva pahare de șampanie. A doua zi dimineața m-am speriat - dacă l-aș lovi cu un cuțit, dar m-am hotărât să-l sperii. Și nu știu de ce am primit așa o lovitură!

Mereu e același lucru, de parcă când mă îmbăt mă duc în parc să caut niște ticăloși să-și bat joc de ei, sau creez subiectele astea pe forum... dimineața mă gândesc, sunt prost?...

Odată, un tip se lovea de mine și eram atât de beat încât am început să-i explic în mod popular că nimic nu va merge rău, pentru că eram „Bloody Mary” (ei erau) și porecla asta mi-a pătruns atât de mult în suflet încât aproape că am le-a strigat tuturor pe care i-am întâlnit: „Sunt Bloody Mary”, din fericire nu era în orașul meu natal

-* l-a sunat pe fostul meu, i-a exprimat tot ce credeam despre el
*mi-a sunat iubita, mi-a spus cat de mult il vreau
*a mâncat shawarma cu folie
* a înjurat un tip pe care l-am întâlnit la un club, deși m-a ajutat și mi-a adus apă
*a dansat un striptease într-un club într-o competiție, a primit locul doi
*a aruncat cu gheață într-un străin
*prietenul bărbatului meu conduce un Hummer galben. Nu am mai văzut așa ceva în Coreea. când mergeam cu toții la petrecere împreună. M-am aplecat din mașina bărbatului meu și, arătând spre Hummer-ul care conducea înainte, am țipat că această mașină este prietena mea.
*ieri am fost la club. când conduceam acasă cu un taxi dimineața, i-am spus șoferului: [traducere din coreeană. literal!] „Mâncarea pe care am mâncat-o tocmai mi-a spus că vrea să iasă!”
*Am și un prieten mongol. M-am urcat pe spatele lui, l-am forțat să mă ducă în spate și am strigat pe toată strada că este calul meu mongol.
dar, în general, au fost mult mai multe, nu vă veți aminti...

I-am scris tipului la ora 4 dimineața „noapte bună, dragă”

Eu și prietenii mei ne-am îmbătat cu coniac, toți s-au dus acasă, iar eu am chemat prostește un taxi (era 3 dimineața) și am fost să-mi văd fostul iubit de care m-am despărțit acum 4 luni (am rămas prieteni). Nu-mi amintesc cum am intrat la intrare, am ajuns în apartamentul lui, i-am spart ușa și am strigat „CĂSĂTORIȚI-MĂ MARAT”, el, săracul, a luat-o razna, m-a târât acasă și într-un duș rece, mi-a dat ceai tare. După două ore am plecat, iar apoi când mi-am dat seama ce am făcut, MI-A fost CHIAR RUȘINE.După aceea ne-am împăcat și suntem încă împreună. După aceea, nu mai beau un pahar de șampanie.


...

02.10.2011, 22:09

Femeia ucisă se plimba cu un tip prin grădină și apoi mi s-a părut că m-a jignit cumva mergând cu câțiva pași înaintea mea, și nu lângă mine. M-am supărat și m-am cățărat într-un copac, dar nici nu a băgat de seamă... a alergat prin grădină o oră și jumătate căutându-mă... și am leșinat calm pe copac și am dormit până dimineață. ...
...
Dar dimineața nu mi-am putut aminti imediat cum am ajuns pe crengi. La dracu cum a fost după
;D;D;D

Interpretare

02.10.2011, 22:42

Mi-e rușine de anumite acțiuni comise în timp ce sunt treaz :) Dar asta e mai aproape de filozofie. În timp ce eram beat... multe lucruri au fost distractive, jenante... nu, îmi pare rău)))))

Elena Lotus

02.10.2011, 23:17

Ieri, dupa ce mi-am dat seama ca telefonul meu (OOO!!!) nu mai este al meu, m-am imbatat.puternic.si (cine ma stie sa nu zici ca beau ca soricelul) apoi am facut ceva...ca doar la prieteni apropiati, in mare secret si apoi ma voi gandi la cine pot spune... Restaurantul Paberti a ramas din nou socat.Acum ma uit la galeria foto in speranta sa vad ce s-a intamplat:(dar eu Nu mi-e rușine... nu... Am crezut doar că sunt decent.

02.10.2011, 23:31

;D;D;D
Mereu am susținut că mătușile nu ar trebui să bea!!! TOATA LUMEA!!!;)

..;D;D;D spui adevarul

02.10.2011, 23:36

O femeie beată este ca o jachetă chinezească de puf: moale și se potrivește.
Galygin

Elena Lotus

02.10.2011, 23:41

Dar bărbaților le place da? Toată lumea poate bea. și mătuși și unchi... trebuie doar să fii atent... azi nu te doare capul... te doare sufletul... vrei să bei ceva? Este doar un cerc vicios;)

03.10.2011, 00:15

Bea orice și tot cât ești tânăr și sănătos :)

03.10.2011, 01:48

furate selectiv de pe forumul femeilor :)

Aproape că fac pipi în coșul de rufe în fața mamei..... confundat cu toaleta.... hopa....

Femeia ucisă se plimba cu un tip prin grădină și apoi mi s-a părut că m-a jignit cumva mergând cu câțiva pași înaintea mea, și nu lângă mine. M-am supărat și m-am cățărat într-un copac, dar nici nu a băgat de seamă... a alergat prin grădină o oră și jumătate căutându-mă... și am leșinat calm pe copac și am dormit până dimineață. ...
...
Dar dimineața nu mi-am putut aminti imediat cum am ajuns pe crengi. La dracu cum a fost după

Pe balcon erau lighene si ghivece in care mama crestea ceapa. M-am enervat “slab” in fiecare dintre aceste vase =((((in paturile mele) gunoiul, sunt aici m-am hotarat sa-ti pis pe verdeata!Pai a continuat sa creasca, apoi a intrat in salata

03.10.2011, 05:35

Eu și prietenii mei ne-am îmbătat cu coniac, toți s-au dus acasă, iar eu am chemat prostește un taxi (era 3 dimineața) și am fost să-mi văd fostul iubit de care m-am despărțit acum 4 luni (am rămas prieteni). Nu-mi amintesc cum am intrat la intrare, am ajuns în apartamentul lui, i-am spart ușa și am strigat „CĂSĂTORIȚI-MĂ MARAT”, el, săracul, a luat-o razna, m-a târât acasă și într-un duș rece, mi-a dat ceai tare. După două ore am plecat, iar apoi când mi-am dat seama ce am făcut, MI-A fost CHIAR RUȘINE.După aceea ne-am împăcat și suntem încă împreună. După aceea, nu mai beau un pahar de șampanie.

Aceasta este o poveste de dragoste foarte reală.
Și despre beneficiile băuturii.

(Băutură, fete, și fericirea va veni la voi.)

Există destul de multe soluții care plutesc pe web pentru emularea multithreading-ului în PHP. Cel mai adesea se bazează pe furci, dar există și variații ale temei de utilizare răsuci, proc_openși așa mai departe.

Toate opțiunile pe care le-am întâlnit nu mi s-au potrivit dintr-un motiv sau altul și a trebuit să-mi scriu singur soluția. Am avut următorul set de cerințe:

  • Utilizarea furcilor;
  • Modul sincron cu păstrarea interfeței în absența extensiilor necesare;
  • Reutilizarea proceselor copil;
  • Schimb complet de date între procese. Acestea. rulați cu argumente și obțineți rezultatul când ați terminat;
  • Abilitatea de a face schimb de evenimente între un proces „fire” copil și procesul principal în timpul funcționării;
  • Lucrul cu un pool de fire în același timp menținând reutilizarea, transmiterea argumentelor și obținerea de rezultate;
  • Gestionarea erorilor de rulare;
  • Timeouts pentru efectuarea lucrărilor, așteptarea lucrului printr-un fir, inițializare;
  • Performanță maximă.

Rezultatul a fost biblioteca AzaThread (fostă CThread).

Descriere

AzaThread oferă o interfață simplă pentru crearea claselor de fire. Care de fapt folosesc procese separate pentru a funcționa asincron, dar nu ar trebui să-ți pese de asta. Puteți trimite evenimente dintr-un fir de execuție, returnați rezultate, utilizați un singur fir de mai multe ori, transmițându-i argumente de pornire sau puteți crea un grup de 16 fire de execuție care vă vor ocupa sarcinile precum prăjiturile calde, fără să acordați atenție faptului că munca se întâmplă. în diferite procese.

În plus, puteți testa cu ușurință performanța bibliotecii în diferite moduri, selectând numărul optim de fire și opțiunea de transfer de date între procese special pentru configurația dvs.

Următoarele extensii sunt necesare pentru funcționarea completă: libevent, posixȘi pcntl.

Biblioteca folosește LibEvent și socket-uri împerecheate pentru comunicarea între procese. Suportă 5 opțiuni pentru transmiterea datelor (argumente, rezultate și date despre evenimente)!

Vă prezint opțiunile imediat cu date de performanță. Testat cu un grup de opt fire de execuție pe un Intel Core i7 2600K 3,40 Ghz (Ubuntu 11.04 pe o mașină virtuală VMware). Sunt date rezultatele medii pentru 10 repetări ale testului în jps (lucrări pe secundă - numărul de sarcini pur și simplu primind argumente și trimitând date pe secundă).

Extensia pentru lucrul cu prize este selectată automat. Dacă este disponibilă, este utilizată extensia prize, care oferă performanțe îmbunătățite. În caz contrar, va fi folosit curent.

Procesul copil ascultă toate semnalele disponibile. În mod implicit, toate (cu excepția SIGWINCH și SIGINFO) sunt urmate de oprire. Dar acest lucru poate fi ușor suprascris prin crearea unei metode în clasa de fir cu numele semnalului. De exemplu sigWinch.

În procesul părinte, toate semnalele sunt, de asemenea, interceptate implicit. Acest lucru poate fi modificat prin setarea parametrului de clasă listenMasterSignals la false . În acest caz, doar SIGCHLD va fi procesat. Puteți adăuga cu ușurință propriile dvs. de gestionare creând o metodă statică numită m<имя сигнала>. De exemplu, mSigTerm.

Dacă un proces copil moare din orice motiv, clasa se va bifurca automat când este lansată o nouă sarcină. Acest lucru se întâmplă neobservat și nu trebuie să vă gândiți deloc la asta. Instanța pur și simplu nu trebuie să fie recreată în cazul oricărei erori.

Procesul copil verifică periodic existența procesului părinte. Dacă moare brusc, copilul se va termina automat.

Toate resursele utilizate de un fir sau de un pool de fire sunt curățate automat atunci când este apelat destructorul. Dar pot fi curățate forțat apelând metoda de curățare. În acest caz, firul/poolul nu mai poate fi folosit.

Cu setările standard, firul de execuție este inițializat în avans, imediat când clasa este creată. Dacă setați parametrul prefork la false , atunci fork-ul va apărea numai în momentul lansării sarcinii.

În general, există destul de mulți parametri personalizabili. Schimbarea numelui procesului copil după fork (parametrul pNumele constructorului), timeout pentru durata execuției sarcinii (timeoutWork), timeout pentru timpul maxim în care procesul copil așteaptă sarcini (timeoutMaxWait), timeout pentru pre- timpul de inițializare (timeoutInit), dimensiunea bufferelor pentru socket-urile de citire (pipeReadSize, pipeMasterReadSize). Puteți dezactiva modul multitasking pentru fire (multitask). În acest caz, de fiecare dată când sarcina este finalizată, procesul copil va muri și va bifurca din nou pentru următoarea lansare. Acest lucru va reduce semnificativ performanța.

Codul este acoperit cu teste și documentat în detaliu; exemple de utilizare pot fi vizualizate și rulate în fișierul example.php. Exemple mai complexe cu gestionarea erorilor pot fi văzute în codul testului unitar.

Există un mod de depanare, care afișează informații foarte detaliate despre ce se întâmplă exact și unde.

Exemple de utilizare

Caracteristica principală este simplitatea maximă. Dacă doriți doar să rulați ceva într-un „fir” separat, următorul cod este suficient:

Clasa ExampleThread extinde Thread (funcția protejată proces() ( // Unii funcționează aici ) ) $thread = nou ExampleThread(); $thread->wait()->run();

Dacă există tot ceea ce este necesar pentru o muncă cu drepturi depline, atunci sarcina va fi finalizată asincron. Dacă nu, atunci totul va funcționa în continuare, dar în modul sincron.

Prin trecerea unui parametru și obținerea unui rezultat, codul va părea puțin mai complicat:

Clasa ExampleThread extinde Thread ( function protected process() ( return $this->getParam(0); ) ) $thread = nou ExampleThread(); $thread->wait()->run(123); $rezultat = $thread->wait()->getResult();

În mod similar, cu o mișcare ușoară a mâinii, adăugăm procesarea evenimentelor din flux:

Clasa ExampleThread extinde Thread ( const EV_PROCESS = "proces"; function protected process() ( $events = $this->getParam(0); for ($i = 0; $i trigger(self::EV_PROCESS, $event_data); ) ) ) // Argument suplimentar. $additionalArgument = 123; $thread->bind(ExampleThread::EV_PROCESS, function($nume_eveniment, $date_event, $additional_arg) ( // procesare eveniment), $additionalArgument); $evenimente = 10; // numărul de evenimente pe care le va genera firul // Pentru a evita așteptarea manuală a firului de execuție înainte de primul apel, // puteți suprascrie proprietatea preforkWait la TRUE în clasa descendentă $thread->wait(); $thread = nou ExempluThread(); $thread->run($evenimente)->wait();

Și, în sfârșit, folosind un grup de opt fire de execuție cu gestionarea erorilor de rulare:

$threads = 8 // Numărul de fire $pool = new ThreadPool("ExampleThread", $threads); $num = 25; // Numărul de sarcini $left = $num; // Numărul de sarcini rămase ( // Dacă există fire libere în pool // Și încă mai avem sarcini de executat while ($pool->hasWaiting() && $left > 0) ( // La pornire, obținem id-ul firului $threadId = $pool->run(); $left--; ) if ($results = $pool->wait($failed)) (foreach ($rezultate ca $threadId => $result) ( / / Sarcină finalizată cu succes // Rezultatul poate fi identificat // prin id-ul firului de execuție ($threadId) $num--; ) ) dacă ($failed) ( // Gestionează erorile de execuție. // Lucrarea este considerată a fi finalizată fără succes // dacă procesul copil a murit în timpul execuției sau // a expirat timeout pentru execuția sarcinii foreach ($failed ca $threadId) ( $left++; ) ) ) while ($num > 0); // Terminați toate procesele copil. Curățăm resursele folosite de bazin. $pool->curățare();

Rezultatele testului de performanță

Am rulat testele pe două mașini cu Ubuntu 11.04.
Primul este Intel Core i3 540 3.07 Ghz.
Al doilea este Intel Core i7 2600K 3,40 Ghz (Ubuntu rulează pe o mașină virtuală VMware).

Vă prezint rezultatele simplu, astfel încât să puteți evalua creșterea productivității. Din nou, acestea sunt rezultatele medii pentru o serie de 10 repetări ale testului în jps (locuri pe secundă - număr de sarcini pe secundă).

Ca sarcină, firele de execuție efectuează următorul gunoi:

Pentru ($i = 0; $i

Primul rezultat este indicat pentru modul de funcționare sincron (fără furci). Nu am încercat 18 și 20 de fire la prima configurație, deoarece deja de 12 performanța a început să scadă.

Numărul de fire Prima configurație Al doilea
0 553 763
1 330 669
2 580 1254
4 1015 2188
8 1040 2618
10 1027 2719
12 970 2739
16 958 2904
18 - 2830
20 - 2730

Adică performanța crește de 2-4 ori sau mai mult, în funcție de procesor!

Codul care rulează o serie de teste cu parametrii necesari se află în fișierul examples/speed_test.php. Astfel, puteți testa cu ușurință performanța și puteți alege numărul optim de fire pentru dvs.

Mă voi bucura foarte mult dacă biblioteca este de folos cuiva. Orice solicitare de funcții sau erori detectate pot fi lăsate pe Github, voi remedia și voi îmbunătăți imediat biblioteca.

NEVROZA INIMA (CARDIOFOBIE). O formă specială de fobie, alături de sindromul de panică, este cardiofobia, care trebuie descrisă mai ales datorită tabloului clinic caracteristic și a frecvenței semnificative. Apare mai ales la tineri, mai des la bărbați, dar și la copii.

Stările de anxietate paroxistică, în care pacienții se tem de încetarea funcției cardiace și de moarte, pot apărea fără prezența unei boli somatice. La începutul următorului atac, apar greață, amețeli, anxietate internă și o ușoară compresie a inimii.

Cu toate acestea, în multe cazuri, fără niciun avertisment, apare un atac sever: bătăi puternice ale inimii resimțite în întregul corp, o ușoară creștere a tensiunii arteriale, o senzație severă de strângere și strângere în zona inimii, dificultăți de respirație, transpirații, amețeli și o senzație de leșin (dar nu de pierdere a conștienței), tremur în tot corpul și frică elementară. Pacientul crede că inima lui se va opri într-o secundă și va cădea mort. Aceasta este frica de autodistrugere și moarte. Când sunt foarte entuziasmați, pacienții aleargă și cer ajutor. Dacă apare un atac de frică în timpul călătoriei într-o mașină, pacientul este forțat să se oprească și să ia o pauză.

După primul atac, apare dezvoltarea fobică. Pacienții își pierd echilibrul mental, trăiesc într-o frică constantă, așteaptă următorul atac sau moarte, experimentând frica de frică (teama de anticipare, fobie). În același timp, nici mesajul terapeutului despre funcționarea normală a inimii și nici convingerea că atacurile anterioare au avut consecințe nu îi ajută. Frecvența atacurilor și intervalele dintre ele sunt neregulate. La intervale, pacientul își monitorizează cu atenție funcțiile cardiace, controlează pulsul și înregistrează cele mai mici abateri ale acestuia. El percepe extrasistolele întâmplătoare ca semne incontestabile ale unei boli cu un rezultat fără speranță.

Pacienții observă cu prudență alte manifestări vegetative, precum și ușoare fluctuații ale stării lor de bine. Pacienții au grijă de ei înșiși, cu greu îndrăznesc să meargă, se străduiesc să elimine tot stresul, grijile și, în primul rând, situațiile dificile pentru a preveni un atac (comportament evaziv). În locul fricii de moarte, în multe cazuri apare tot mai mult frica de frică și de situațiile care provoacă frică.

CONDIȚII DE APARIȚIE. Motivul primului atac cardiofob este adesea un conflict acut și suprasolicitare, separarea și dezamăgirea, o situație de singurătate și abandon, precum și anxietatea în cazul morții cardiace a cuiva apropiat.

A ști că moartea cardiacă se poate întâmpla întotdeauna, chiar și la cei tineri și sănătoși, devine un factor îngrijorător. Consumul intens de cafea și nicotină poate declanșa acest proces. Începutul vine adesea din copilărie. Sunt afectați în mare parte copiii răsfățați și dependenți, cu o dependență pronunțată de mamă, în mare măsură cu atitudini ambivalente: așteptarea iubirii, pe de o parte, și dorința de independență cu impulsuri agresive, pe de altă parte, cu fantezii contradictorii de atașament și separare. Asemenea atitudini sunt deosebit de periculoase atunci când conexiunile sunt întrerupte, apar despărțiri și dezamăgiri. Un cardiofob trăiește adesea cu frica de separare înainte de a realiza că își dorește asta și îi este frică de asta. Probleme comune cu părinții și conflictele cu partenerii apar în mod regulat.

TRATAMENT
Dacă într-o stare acută prezența unui medic și o conversație cu acesta nu provoacă ameliorare, sunt indicate tranchilizante sau beta-blocante. Ca și alți pacienți cu nevroze cu frică, mulți fobi încearcă să se automediceze cu alcool; dar efectul său este insuficient, iar pericolul de a deveni dependent de alcool este mare. Farmacoterapia este doar un remediu auxiliar, în primul rând în cazurile acute, precum și un remediu inițial eficient.

Psihoterapia este decisivă. Cu cât începe mai devreme, cu atât mai bine. Studierea cauzelor și a situațiilor conflictuale imediat după primele atacuri cardiofobe poate opri dezvoltarea fobică ulterioară. Tratamentul ulterior este mai dificil și este necesară psihoterapia pe termen lung.

Pentru acestea și alte tulburări de anxietate este indicată în special terapia comportamentală (confruntare cu excitare, terapie cognitivă, antrenament pentru încrederea în sine). O trăsătură distinctivă a antrenamentului pentru evitarea anxietății este că funcționează pe un model de desensibilizare (la condițiile corespunzătoare situațiilor cotidiene), iar antrenamentul pentru managementul anxietății folosește imersiunea forțată într-o situație fobică (inundare) și formarea de strategii de coping. Tulburările de anxietate severe necesită tratament clinic folosind diverse modele de psihoterapie.

Există destul de multe soluții care plutesc pe web pentru emularea multithreading-ului în PHP. Cel mai adesea se bazează pe furci, dar există și variații ale temei folosind curl, proc_open etc.

Dintr-un motiv sau altul, toate variantele pe care le-am întâlnit nu mi s-au potrivit și a trebuit să-mi scriu singur soluția.
Am avut următorul set de cerințe:

  • Utilizarea furcilor;
  • Modul sincron cu păstrarea interfeței în absența extensiilor necesare;
  • Reutilizarea proceselor copil;
  • Schimb complet de date între procese. Acestea. rulați cu argumente și obțineți rezultatul când ați terminat;
  • Abilitatea de a face schimb de evenimente între un proces „fire” copil și procesul principal în timpul funcționării;
  • Lucrul cu un pool de fire în același timp menținând reutilizarea, transmiterea argumentelor și obținerea de rezultate;
  • Gestionarea erorilor de rulare;
  • Timeouts pentru efectuarea lucrărilor, așteptarea lucrului printr-un fir, inițializare;
  • Performanță maximă;
Rezultatul este o bibliotecă AzaThread(nume vechi - CThread).

Pentru cei nerăbdători, iată un link către sursă:
github.com/Anizoptera/AzaThread

Descriere

AzaThread oferă o interfață simplă pentru crearea claselor de fire. Care de fapt folosesc procese separate pentru a funcționa asincron, dar nu ar trebui să-ți pese de asta. Puteți trimite evenimente dintr-un fir de execuție, puteți returna rezultate, puteți utiliza un fir de mai multe ori, trecându-i argumente de lansare sau puteți crea un grup de 16 fire de execuție care vă găzduiesc sarcinile, cum ar fi prăjiturile calde, fără să acordați atenție faptului că munca se desfășoară în diferite moduri. proceselor.

În plus, puteți testa cu ușurință performanța bibliotecii în diferite moduri, selectând numărul optim de fire și opțiunea de transfer de date între procese special pentru configurația dvs.

Următoarele extensii sunt necesare pentru funcționarea completă: libevent, posixȘi pcntl.

Biblioteca folosește LibEvent și socket-uri împerecheate pentru comunicarea între procese. Suportă 5 opțiuni pentru transmiterea datelor (argumente, rezultate și date despre evenimente)!

Vă prezint opțiunile imediat cu date de performanță. Testat cu un grup de opt fire de execuție pe un Intel Core i7 2600K 3,40 Ghz (Ubuntu 11.04 pe o mașină virtuală VMware). Sunt date rezultatele medii pentru 10 repetări ale testului în jps (lucrări pe secundă - numărul de sarcini pur și simplu primind argumente și trimitând date pe secundă).

Extensia pentru lucrul cu prize este selectată automat. Dacă este disponibilă, este utilizată extensia prize, care oferă performanțe îmbunătățite. În caz contrar, va fi folosit curent.

Procesul copil ascultă toate semnalele disponibile. În mod implicit, toate (cu excepția SIGWINCH și SIGINFO) sunt urmate de oprire. Dar acest lucru poate fi ușor suprascris prin crearea unei metode în clasa de fir cu numele semnalului. De exemplu sigWinch.

În procesul părinte, toate semnalele sunt, de asemenea, interceptate implicit. Acest lucru poate fi modificat prin setarea parametrului de clasă ascultăMasterSignals la fals. În acest caz, doar SIGCHLD va fi procesat. Puteți adăuga cu ușurință propriile dvs. de gestionare creând o metodă statică numită m< имя сигнала > . De exemplu mSigTerm.

Dacă un proces copil moare dintr-un motiv oarecare, clasa se va bifurca automat când este lansată o nouă sarcină. Acest lucru se întâmplă neobservat și nu trebuie să vă gândiți deloc la asta. Instanța pur și simplu nu trebuie să fie recreată în cazul oricărei erori.

Procesul copil verifică periodic existența procesului părinte. Dacă moare brusc, copilul se va termina automat.

Toate resursele utilizate de un fir sau de un pool de fire sunt curățate automat atunci când este apelat destructorul. Dar ele pot fi șterse forțat apelând metoda curăță. În acest caz, firul/poolul nu mai poate fi folosit.

Cu setările standard, firul de execuție este inițializat în avans, imediat când clasa este creată. Dacă setați parametrul prefurcă la fals, atunci bifurcația va apărea numai în momentul lansării sarcinii.

În general, există destul de mulți parametri personalizabili. Schimbarea numelui procesului copil după un fork (parametrul pNume constructor), timeout pentru durata sarcinii ( timeoutWork), timeout pentru timpul maxim pe care un proces copil poate aștepta sarcini ( timeoutMaxWait), timeout pentru timpul de pre-inițializare ( timeoutInit), dimensiunile bufferului de citire a soclului ( pipeReadSize, pipeMasterReadSize).
Puteți dezactiva modul multitasking pentru fire ( multitask). În acest caz, de fiecare dată când sarcina este finalizată, procesul copil va muri și va bifurca din nou pentru următoarea lansare. Acest lucru va reduce semnificativ performanța.

Codul este acoperit cu teste și documentat în detaliu; exemple de utilizare pot fi vizualizate și rulate în fișier exemplu.php.
Exemple mai complexe cu gestionarea erorilor pot fi văzute în codul testului unitar.

Există un mod de depanare care afișează informații foarte detaliate despre ce se întâmplă exact și unde.

Exemple de utilizare

Caracteristica principală este simplitatea maximă. Dacă doriți doar să rulați ceva într-un „fir” separat, următorul cod este suficient:
clasa ExampleThread extinde Thread (funcția protejată proces() ( // Unii funcționează aici ) ) $thread = nou ExampleThread(); $thread->wait()->run();
Dacă există tot ceea ce este necesar pentru o muncă cu drepturi depline, atunci sarcina va fi finalizată asincron. Dacă nu, atunci totul va funcționa în continuare, dar în modul sincron.

Prin trecerea unui parametru și obținerea rezultatului, codul va părea puțin mai complicat:
clasa ExampleThread extinde Thread ( function protected process() ( return $this->getParam(0); ) ) $thread = nou ExampleThread(); $thread->wait()->run(123); $rezultat = $thread->wait()->getResult();

În mod similar, cu o mișcare ușoară a mâinii, adăugăm procesarea evenimentelor din flux:
clasa ExampleThread extinde Thread ( const EV_PROCESS = „proces”; funcția protejată proces() ( $evenimente = $this->getParam(0); pentru ($i = 0; $i< $events; $i++) { $event_data = $i; $this->trigger(self::EV_PROCESS, $event_data); ) ) ) // Argument suplimentar. $additionalArgument = 123; $thread->bind(ExampleThread::EV_PROCESS, function($nume_eveniment, $date_event, $additional_arg) ( // procesare eveniment), $additionalArgument); $evenimente = 10; // numărul de evenimente pe care le va genera firul // Pentru a evita așteptarea manuală a firului de execuție înainte de primul apel, // puteți suprascrie proprietatea preforkWait la TRUE în clasa descendentă $thread->wait(); $thread = nou ExempluThread(); $thread->run($evenimente)->wait();

Și, în sfârșit, folosind un grup de opt fire de execuție cu gestionarea erorilor de rulare:
$threads = 8 // Numărul de fire $pool = new ThreadPool("ExampleThread", $threads); $num = 25; // Numărul de sarcini $left = $num; // Numărul de sarcini rămase ( // Dacă există fire libere în pool // Și încă mai avem sarcini de executat while ($pool->hasWaiting() && $left > 0) ( // La pornire, obținem id-ul firului $threadId = $pool->run(); $left--; ) if ($results = $pool->wait($failed)) (foreach ($rezultate ca $threadId => $result) ( / / Sarcină finalizată cu succes // Rezultatul poate fi identificat // prin id-ul firului de execuție ($threadId) $num--; ) ) dacă ($failed) ( // Gestionează erorile de execuție. // Lucrarea este considerată a fi finalizată fără succes // dacă procesul copil a murit în timpul execuției sau // a expirat timeout pentru execuția sarcinii foreach ($failed ca $threadId) ( $left++; ) ) ) while ($num > 0); // Terminați toate procesele copil. Curățăm resursele folosite de bazin. $pool->curățare();

Rezultatele testului de performanță

Am rulat testele pe două mașini cu Ubuntu 11.04.
Primul este Intel Core i3 540 3.07 Ghz
Al doilea este Intel Core i7 2600K 3,40 Ghz (Ubuntu rulează pe o mașină virtuală VMware)

Vă prezint rezultatele simplu, astfel încât să puteți evalua creșterea productivității.
Din nou, acestea sunt rezultatele medii pentru o serie de 10 repetări de test în jps (lucrări pe secundă - număr de sarcini pe secundă).

Ca sarcină, firele de execuție efectuează următorul gunoi:
pentru ($i = 0; $i< 1000; $i++) { $r = mt_rand(0, PHP_INT_MAX) * mt_rand(0, PHP_INT_MAX); }
Primul rezultat este indicat pentru modul de funcționare sincron (fără furci).
Nu am încercat 18 și 20 de fire la prima configurație, deoarece deja de 12 performanța a început să scadă.

Numărul de fire Prima configurație Al doilea
0 553 763
1 330 669
2 580 1254
4 1015 2188
8 1040 2618
10 1027 2719
12 970 2739
16 958 2904
18 - 2830
20 - 2730

Adică performanța crește de 2-4 ori sau mai mult, în funcție de procesor!

Codul care rulează o serie de teste cu parametrii necesari se află în fișier exemple/test_viteză.php. Astfel, puteți testa cu ușurință performanța și puteți alege numărul optim de fire pentru dvs.

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 multithreading poate fi realizat î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 Thread::start este apelat, 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 de finalizat) 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 de îndată 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).

Este o bună practică pentru lucrători și piscine să își curețe întotdeauna sarcinile de îndată ce le-au finalizat ș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 Threaded funcția publică __construct($tm) ( $this->threadedMember = $tm; var_dump($this->threadedMember-> date); // 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(); ) ) ), $contor); $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.