Nit rasprava o stvarima php. Odabir PHP verzije za Windows. Put Jedija - korištenje proširenja PCNTL

02.04.2020 Vijesti

Majka moje dobre prijateljice izgubila je kofer na letu iz Sankt Peterburga za Moskvu, pa ju je čekao daljnji let na toplije obale, a sada je već bila u odmaralištu - bez kupaćeg kostima, sandala i samo s T -košulja iz njezine ručne prtljage. Za stara vremena dao sam joj par savjeta što da radi i kamo da trči, a danas sam odlučio ovdje napisati sve što znam na zadanu temu.

Da vam objasnim gdje sam tako pametan, podsjetit ću vas da sam svojedobno radio na zemaljskim uslugama za nekoliko zračnih prijevoznika, uključujući i rješavanje određenih problema vezanih uz pretragu prtljage. Pa, plus moje vlastito iskustvo leta, naravno. Međutim, jer Napustio sam industriju zrakoplovnih usluga prije nekoliko godina, možda su se neke nijanse promijenile - ako je tako, sa zahvalnošću ću prihvatiti komentare na tu temu i ispraviti informacije u objavi.

Počet ću s ovim Što trebate učiniti da spriječite gubitak svoje prtljage:
1. S kofera otkinite sve oznake i naljepnice s prethodnih putovanja, čak i one male s barkodom, koje su često posebno zalijepljene na sam kofer - mogu zbuniti automatski sustav skeniranje i razvrstavanje prtljage.
2. Objesite pločicu s imenom na svoj kofer (torbu, kutiju, paket - općenito, sve što prijavljujete kao prtljagu): možete unaprijed kupiti opciju za višekratnu upotrebu ili uzeti papirnatu pločicu na šalteru za prijavu - obično sve više ili manje pristojne zrakoplovne tvrtke daju ih bez ograničenja. A Emirates, na primjer, općenito ima izvrsne plastične oznake na izdržljivom kabelu koji može trajati jako dugo:

Stari paranoici mogu učiniti poput mene: uvijek imam višekratnu plastičnu pločicu iz Samsonite seta na koferu s mojom stalnom kućnom adresom, telefonskim brojem i e-poštom, a kad letim negdje na odmor, dodatno okačim papirnatu ceduljicu na kojoj naznačim datume boravka u novom mjestu i sve moguće kontakte (naziv i adresu hotela, njegov lokalni telefonski broj, ako postoji, i moje ime i prezime, naravno).
3. Provjerite je li na šalteru za prijavu na vašu prtljagu zalijepljena pločica za prtljagu koju je ispisao agent za prijavu - s šifrom grada u koji letite i brojem leta.
4. Ako imate nekoliko povezanih letova, o tome obavijestite agenta za prijavu i odredite do kojeg mjesta želite predati svoju prtljagu. U nekim slučajevima, prtljagu ćete morati preuzeti u jednoj ili drugoj zračnoj luci duž rute, bez obzira na vašu želju: to se, na primjer, odnosi na transfere između zračnih luka (Orly i Charles de Gaulle u Parizu, Domodedovo - Sheremetyevo - "Vnukovo). " u Moskvi), odvojenim terminalima (terminali 1 i 2 u Frankfurtu) ili na prvoj točki dolaska u SAD ili Meksiko - ovo je carinski zahtjev u ovim zemljama: pretpostavimo da letite Moskva-Washington-Phoenix, oznaka za prtljagu izdaje se za sva tri segmenta u Phoenixu, ali u Washingtonu će prtljagu trebati fizički preuzeti, proći carinu i ponovno prijaviti. Također, ako prijavljujete dječja kolica koja ste smjeli uzeti prije ukrcaja avionom ili životinjom, vjerojatno ćete ga morati preuzeti na tranzitnoj točki. Općenito, u slučaju složene rute s presjedanjem, bolje je unaprijed razjasniti detalje o kretanju prtljage u pozivnom centru zrakoplovne tvrtke ili, u ekstremnim slučajevima, prilikom prijave.
5. Učinite svoju prtljagu vidljivom: kašnjenje prtljage nije uvijek krivnja osoba koje rukuju prtljagom ili kvarova u sustavu sortiranja. Ponekad će drugi putnik odsutan duhom, umoran nakon dugog leta, s vrtuljka za prtljagu uzeti istu crnu Samsonite ili neuglednu sportsku torbu kao što je vaša. Stoga označite svoju prtljagu: objesite hrpu svijetlih vrpci ili malu meku igračku na ručku, zalijepite veliku naljepnicu ili jednostavno dajte prednost neobičnoj boji pri odabiru kovčega.

Što se ne smije predati u prtljagu?
Zapamtite, sve zrakoplovne tvrtke i zračne luke gube prtljagu. Naravno, statistike su različite za svakoga, ali čak i najpouzdaniji zrakoplovni prijevoznici mogu izgubiti ili odgoditi prtljagu, pa čak i u najmanjoj zračnoj luci, gdje će jedan rukovatelj prtljage prevesti kolica s koferima direktno od šaltera za prijavu na let do zrakoplova. Stoga vam savjetujem da u svoju ručnu prtljagu uvijek ponesete:
- važni dokumenti, uključujući i one koji nisu potrebni tijekom leta (na primjer, na mom zadnjem putovanju u Sankt Peterburg morao sam promijeniti svoju dozvolu, a sa sobom sam u ručnoj prtljazi ponio vjenčani list i sve vrste iskaznica iz autoškola)
- ključevi (u kombinaciji s oznakom s vašom adresom to može biti opasno)
- novac, nakit (bez komentara)
- skupa krhka oprema
- lijekove koje redovito uzimate, u količini potrebnoj za let, te s malom rezervom u slučaju da morate tražiti analog u stranoj zemlji ili gradu. Lijekove na recept koje ne možete kupiti u slučaju gubitka prtljage ponesite sa sobom u količini potrebnoj za cijelo putovanje.
- nešto što bi moglo biti potrebno hitno po dolasku (npr. Punjač za telefon
- nešto što za vas osobno ima sentimentalnu vrijednost: ponekad se prtljaga zauvijek izgubi, a ako vam gubitak osobnog dnevnika slama srce, bolje ga je ostaviti kod kuće ili ponijeti sa sobom u avion

Poučna priča: za vrijeme mog rada u Lufthansi u Sankt Peterburgu, u ured nam je dotrčao bračni par iz SAD-a, kršeći ruke - nije stigla njihova prtljaga u kojoj su bili vrlo važni dokumenti za sudski postupak za posvajanje, suđenje je bilo sljedeći dan. Naravno, zrakoplovna tvrtka je kriva za gubitak prtljage, ali tko ima koristi od toga? Da biste izbjegli takvu situaciju, bilo je dovoljno važne papire jednostavno staviti u ručnu prtljagu.

Dakle, stigli ste i niste pronašli svoju prtljagu na traci za prtljagu. Što uraditi?
1. Ako ste predali u prtljagu nešto drugo osim običnih kofera: skije, violončelo, plazma panel veličine zida, dječja kolica, živu mramornu dogu, provjerite postoji li posebno mjesto za izdavanje tzv. prevelika prtljaga ili glomazna prtljaga - prtljaga slična onoj koju sam gore opisao često se utovaruje u poseban odjeljak i istovaruje zasebno, ručno. Ako se ni tamo ne nađe vaša prtljaga
2. Idite na šalter traženja prtljage ili Lost & Found. Tamo ćete morati ispuniti poseban obrazac sa detaljne informacije o vašoj prtljazi: ruta, izgled, kratki popis sadržaja, vaši kontakti u mjestu prebivališta i boravišta. Također, u usluzi traženja prtljage vjerojatnije je da ćete vidjeti ovakvu tablicu prtljage:

U skladu s ovom klasifikacijom bit će kodirana vaša prtljaga koja nedostaje i, kako razumijete, ova dva kovčega bit će kodirana isto:

Stoga slobodno dodajte dodatne pojedinosti u opis i nemojte preskočiti klauzulu o sadržaju. U pravilu, kada prvi put ispunjavate izvješće o kašnjenju prtljage, od vas će se tražiti da navedete nekoliko stavki sadržaja po kojima se vaša torba može identificirati ako nema identifikacijskih oznaka s vanjske strane i torba će se morati otvoriti (ako torba je otvorena, stavit ćete obavijest o tome). Loš primjer: majica kratkih rukava / knjiga / vlažne maramice, dobar primjer: jarko crveni bikini / katalog reprodukcija Malevicha / glačalo na preklop. Nakon što ispunite prijavu, djelatnik službe za traženje prtljage dat će vam broj u formatu XXXYY11111, gdje je XXX šifra dolazne zračne luke, YY je šifra dolazne zračne luke + 5 znamenki serijskog broja aplikacije: na primjer, JFKLH12345, ako letjeli ste s Lufthansom u zračnu luku Kennedy u New Yorku. Zapamtite ili zapišite ovaj broj - tako ćete najlakše pronaći svoju prijavu u budućim prijavama.
Pomoću istog broja možete i SAMI provjeriti status pretrage (iz nekog razloga link nestaje: ako vam ne radi, guglajte World Tracer Online i doslovno drugi link - s naslovom Baggage Tracing na web stranici worldtracer.aero - je ono što vam treba), jer dolazak do lost&found često je vrlo teško
3. Pokušajte kontaktirati ured svoje zrakoplovne tvrtke u zračnoj luci dolaska: ponekad (naglašavam - PONEKAD!) ako niste letjeli kući, već na mjesto privremenog boravka (odmor, poslovno putovanje), zrakoplovna tvrtka može osigurati set toaletnih potrepština (ima ih Lufthansa). uključena je velika majica kratkih rukava, četkica i pasta za zube, češalj, mala pakiranja šampona i gela za tuširanje, paket praška za pranje rublja itd.) ili uplatite malu gotovinu za male troškove na spot (gotovinsko plaćanje na licu mjesta).

Što će se sljedeće dogoditi?
Vaša datoteka (tzv. AHL) će ići u centralizirani sustav pretraživanja prtljage (World Tracer). Svi nepreuzeti predmeti prtljage ulaze u isti sustav pretraživanja, bez obzira jesu li pronađeni bez oznake u kutovima i pukotinama prostora za prtljagu ili su ostali na vrpci za prtljagu; za svaki od ovih predmeta vodi se datoteka formata XXXYY11111 također stvoren, samo drugačijeg podtipa – tzv. izvještaj na ruke ili OHD. Ako se podaci iz AHL i OHD datoteke poklapaju (prezime, opis kofera, ruta itd.), obje postaje (gdje je prijavljen gubitak prtljage i gdje je pronađena nepreuzeta prtljaga) će dobiti obavijest, a zatim to je stvar tehnologije: ponovna provjera i u slučaju uspjeha prosljeđivanje prtljage u željeni grad. Naravno, tu je uključeno i puno ručnog rada - razmjena poruka, odbijanje sličnih ali ne istih kofera, plus odgovaranje na više Telefonski pozivi- općenito, osoblju službe traženja prtljage nikada nije dosadno.
Približna statistika: više od 90% izgubljene prtljage pronađe se u prva 3 dana potrage, 3% se izgubi zauvijek.
Što možeš učiniti?
1. Ako po dolasku morate kupiti nešto hitno (od četkice za zube do poslovnog odijela), svakako sačuvajte račune za kasniju naknadu. Ipak, trebali biste izbjegavati nepotrebne skupe kupnje, kasnije ću objasniti zašto.
2. Slijedeći nove korake, napravite najdetaljniji popis sadržaja, po mogućnosti s bojom, markom i približan trošak sve, idealno Engleski jezik(jer će u suprotnom zaposlenik zrakoplovne kompanije morati prevesti ovaj popis za uključivanje u sustav), kontaktirajte zrakoplovnog prijevoznika i pošaljite im ovaj popis, on će biti dodan u aplikaciju za traženje prtljage. Prvih 5 dana potragu za prtljagom provodi zračna luka dolaska, zatim potraga prelazi u odgovornost prijevoznika (zrakoplovnog prijevoznika navedenog u broju prijave - sjećate se JFKLH12345?), a nakon 21 dana vi može podnijeti zahtjev za konačnu naknadu.
3. Ako nakon 21 dana od datuma podnošenja izjave o izgubljenoj prtljazi ista nije pronađena, obratite se prijevozniku i zatražite odštetu. Ako se ne varam zastara je 2 godine t.j. Možete podnijeti zahtjev za naknadu štete u roku od dvije godine od dana podnošenja zahtjeva za štetu.

Isplata odštete.
Da biste platili odštetu, morat ćete se obratiti predstavništvu svoje zrakoplovne kompanije sa zahtjevom za isplatu, dokumentima koji potvrđuju let i činjenicu gubitka prtljage (ukrcajne karte, oznake za prtljagu, broj zahtjeva za gubitak prtljage, podaci o plaćanju). Ako se ne varam, u Ruskoj Federaciji odluka o odšteti mora biti pravno razmotrena u roku od 30 dana. Od vas se također može tražiti da procijenite troškove sadržaja i, ako je moguće, dostavite račune za kupnju kovčega i stvari u njemu (razumijem da je to u većini slučajeva nerealno, ali ovo je dio procedure).
Prije su se plaćanja vršila na temelju težine predane prtljage - oko 20 dolara po kilogramu. Kasnije je promijenjen sustav plaćanja te je odgovornost zrakoplovnih prijevoznika ograničena na 1.000 konvencionalnih jedinica (trošak konvencionalne jedinice obračunava se unutar zrakoplovnog prijevoznika), što je u vrijeme mog rada odgovaralo otprilike 1.300 eura. Oni. čak i ako donesete račun za kupnju Louis Vuitton kofera napravljenog od tisuću koža bolivijskog gekona i punjenog dijamantima, nećete dobiti više od 1300 eura.

Ponekad je potrebno izvršiti nekoliko radnji istovremeno, na primjer, provjeriti promjene u jednoj tablici baze podataka i napraviti izmjene u drugoj. Štoviše, ako jedna od operacija (na primjer, provjera promjena) oduzima puno vremena, očito je da sekvencijalno izvršavanje neće osigurati uravnoteženje resursa.

Za rješavanje ove vrste problema, programiranje koristi multithreading - svaka operacija se nalazi u zasebnoj niti s dodijeljenom količinom resursa i radi unutar nje. Ovim pristupom svi će se zadaci obavljati zasebno i neovisno.

Iako PHP ne podržava multithreading, postoji nekoliko metoda za njegovu emulaciju, o čemu će biti riječi u nastavku.

1. Pokretanje nekoliko kopija skripte - jedna kopija po operaciji

//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" ) (pronađi_još jednu(); )

Kada izvršimo ovu skriptu bez parametara, ona automatski pokreće dvije svoje kopije, s ID-ovima operacija ("thread=make_me_happy" i "thread=make_me_rich"), koje pokreću izvršavanje potrebnih funkcija.

Na taj način postižemo željeni rezultat - dvije operacije se izvode istovremeno - ali to, naravno, nije multithreading, već jednostavno štaka za istovremeno obavljanje zadataka.

2. Put Jedija - korištenje ekstenzije PCNTL

PCNTL je proširenje koje vam omogućuje potpuni rad s procesima. Osim upravljanja, podržava slanje poruka, provjeru statusa i postavljanje prioriteta. Ovako izgleda prethodna skripta koja koristi PCNTL:

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

Izgleda prilično zbunjujuće, prođimo red po red.

U prvom retku “račvamo” trenutni proces (fork kopira proces uz očuvanje vrijednosti svih varijabli), dijeleći ga na dva procesa (tekući i dijete) koji se izvode paralelno.

Da shvatimo gdje smo ovaj trenutak, u procesu dijete ili majka, funkcija pcntl_fork vraća 0 za dijete i ID procesa za majku. Stoga, u drugom retku gledamo $pid, ako je nula, onda smo u procesu dijete - izvršavamo funkciju, u suprotnom smo u majci (linija 4), zatim kreiramo drugi proces i na sličan način izvršiti zadatak.

Proces izvršavanja skripte:

Dakle, skripta stvara još 2 procesa djeteta, koji su njezine kopije i sadrže iste varijable sa sličnim vrijednostima. I koristeći identifikator koji vraća funkcija pcntl_fork, saznajemo u kojoj se niti trenutno nalazimo i izvodimo potrebne radnje.

Čini se da PHP programeri rijetko koriste paralelnost. Neću govoriti o jednostavnosti sinkronog koda; jednonitno programiranje je, naravno, jednostavnije i jasnije, ali ponekad mala upotreba paralelizam može donijeti značajna poboljšanja performansi.

U ovom ćemo članku pogledati kako se višenitnost može postići u PHP-u pomoću proširenja pthreads. Da biste to učinili, trebat će vam instalirana ZTS (Zend Thread Safety) verzija PHP 7.x, zajedno s instalirano proširenje pthreads v3. (U vrijeme pisanja, u PHP 7.1, korisnici će morati instalirati iz glavne grane u repozitoriju pthreads - pogledajte ekstenziju treće strane.)

Malo pojašnjenje: pthreads v2 je namijenjen za PHP 5.x i više nije podržan, pthreads v3 je za PHP 7.x i aktivno se razvija.

Nakon takve digresije, prijeđimo odmah na stvar!

Obrada jednokratnih zadataka

Ponekad želite obraditi jednokratne zadatke na višenitni način (na primjer, izvršavanje nekog I/O-vezanog zadatka). U takvim slučajevima možete koristiti klasu Thread za stvaranje nove niti i pokretanje neke obrade na zasebnoj niti.

Na primjer:

$task = nova klasa proširuje nit ( privatni $response; javna funkcija run() ( $content = file_get_contents("http://google.com"); preg_match("~ (.+)~", $content, $matches); $this->response = $matches; ) ); $task->start() && $task->join(); var_dump($task->response); // niz (6) "Google"

Ovdje je run metoda naša obrada, koja će se izvršiti unutar nove niti. Kada se pozove Thread::start, stvara se nova nit i poziva se metoda pokretanja. Zatim pridružujemo podređenu nit natrag glavnoj niti pozivom Thread::join, koji će blokirati dok podređena nit ne završi s izvođenjem. Ovo osigurava da zadatak završi s izvršavanjem prije nego što pokušamo ispisati rezultat (koji je pohranjen u $task->response).

Možda nije poželjno zagađivati ​​klasu dodatnim odgovornostima povezanim s logikom toka (uključujući odgovornost za definiranje metode pokretanja). Takve klase možemo razlikovati nasljeđujući ih od klase Threaded. Zatim se mogu pokrenuti unutar druge niti:

Zadatak klase proširuje Threaded ( public $response; public function someWork() ( $content = file_get_contents("http://google.com"); preg_match("~ (.+) ~", $content, $matches); $ this->response = $matches; ) ) $task = new Task; $thread = new class($task) extends Thread (privatni $task; javna funkcija __construct(Threaded $task) ( $this->task = $task; ) javna funkcija run() ( $this->task->someWork( ); ) ); $thread->start() && $thread->join(); var_dump($task->response);

Bilo koja klasa koju je potrebno izvoditi u zasebnoj niti mora naslijediti od Threaded klase. To je zato što pruža potrebne mogućnosti za izvođenje obrade na različitim nitima, kao i implicitnu sigurnost i korisna sučelja (kao što je sinkronizacija resursa).

Pogledajmo hijerarhiju klasa koju nudi proširenje pthreads:

Threaded (implementira Traversable, Collectable) Thread Worker Volatile Pool

Već smo pokrili i naučili osnove klasa Thread i Threaded, a sada pogledajmo ostale tri (Worker, Volatile i Pool).

Ponovno korištenje niti

Pokretanje nove niti za svaki zadatak koji treba paralelizirati prilično je skupo. To je zato što se arhitektura zajedničkog ništa mora implementirati u pthreads kako bi se postigla višenitnost unutar PHP-a. Što znači da cijeli kontekst izvršenja trenutne instance PHP interpretera (uključujući svaku klasu, sučelje, značajku i funkciju) mora biti kopiran za svaku stvorenu nit. Budući da to ima primjetan učinak na izvedbu, stream treba uvijek ponovno koristiti kad god je to moguće. Niti se mogu ponovno koristiti na dva načina: korištenjem radnika ili korištenjem skupova.

Klasa Worker koristi se za sinkrono izvođenje niza zadataka unutar druge niti. To se postiže stvaranjem nove Worker instance (koja stvara novu nit), a zatim guranjem zadataka na stog te zasebne niti (pomoću Worker::stack).

Evo malog primjera:

Class Task extends Threaded ( private $value; public function __construct(int $i) ( $this->value = $i; ) public function run() ( usleep(250000); echo "Task: ($this->value) \n"; ) ) $radnik = novi radnik(); $radnik->start(); for ($i = 0; $i stack(new Task($i)); ) while ($worker->collect()); $radnik->gašenje();

U gornjem primjeru, 15 zadataka za novi objekt $worker gura se na stog putem metode Worker::stack, a zatim se obrađuju redoslijedom kojim su gurnuti. Metoda Worker::collect, kao što je gore prikazano, koristi se za čišćenje zadataka čim završe s izvršenjem. S njim, unutar while petlje, blokiramo glavnu nit dok se svi zadaci na stogu ne dovrše i obrisu - prije nego što pozovemo Worker::shutdown. Rano prekidanje radnika (tj. dok još ima zadataka koje je potrebno dovršiti) i dalje će blokirati glavnu nit dok svi zadaci ne dovrše svoje izvršenje, samo da se zadaci neće skupljati u smeće (što za sobom povlači curenje memorije).

Klasa Worker nudi nekoliko drugih metoda vezanih uz njen stog zadataka, uključujući Worker::unstack za uklanjanje zadnjeg složenog zadatka i Worker::getStacked za dobivanje broja zadataka u izvršnom stogu. Radnički stog sadrži samo zadatke koje je potrebno izvršiti. Nakon što je zadatak na stogu dovršen, on se uklanja i stavlja na poseban (unutarnji) stog za sakupljanje smeća (koristeći metodu Worker::collect).

Drugi način za ponovno korištenje niti u više zadataka je korištenje skupa niti (putem klase Pool). Skup niti koristi grupu radnika za omogućavanje izvršavanja zadataka istovremeno, u kojem je faktor konkurentnosti (broj niti skupa s kojima radi) postavljen kada se skup kreira.

Prilagodimo gornji primjer za korištenje skupa radnika:

Class Task extends Threaded ( private $value; public function __construct(int $i) ( $this->value = $i; ) public function run() ( usleep(250000); echo "Task: ($this->value) \n"; ) ) $pool = new Pool(4); for ($i = 0; $i submit(new Task($i)); ) while ($pool->collect()); $pool->shutdown();

Postoji nekoliko značajnih razlika kada se koristi bazen za razliku od radnika. Prvo, bazen ne treba pokretati ručno; on počinje izvršavati zadatke čim postanu dostupni. Drugo, mi poslati zadaci u bazen, ne stavite ih na hrpu. Osim toga, klasa Pool ne nasljeđuje Threaded i stoga se ne može proslijediti drugim nitima (za razliku od Worker).

Dobra je praksa za radnike i skupove da uvijek očiste svoje zadatke čim ih dovrše, a zatim ih sami ručno prekinu. Niti stvorene pomoću klase Thread također moraju biti pripojene nadređenoj niti.

pthreads i (ne)promjenjivost

Posljednja klasa koje ćemo se dotaknuti je Volatile, novi dodatak pthreads v3. Nepromjenjivost je postala važan koncept u pthreadovima jer bez nje performanse značajno pate. Stoga su prema zadanim postavkama svojstva Threaded klasa koje su same Threaded objekti sada nepromjenjiva i stoga se ne mogu prebrisati nakon njihove početne dodjele. Trenutačno se preferira eksplicitna promjenjivost za takva svojstva, a još uvijek se može postići pomoću nove klase Volatile.

Pogledajmo primjer koji će pokazati nova ograničenja nepromjenjivosti:

Zadatak klase proširuje Threaded // klasu Threaded ( javna funkcija __construct() ( $this->data = new Threaded(); // $this->data nije moguće prebrisati, jer je to svojstvo Threaded klase Threaded ) ) $task = new class(new Task()) extends Thread ( // klasa Threaded, budući da Thread proširuje Threaded javnu funkciju __construct($tm) ( $this->threadedMember = $tm; var_dump($this->threadedMember-> podaci); // object(Threaded)#3 (0) () $this->threadedMember = new StdClass(); // nevažeći, budući da je svojstvo Threaded član Threaded klase ));

Navojna svojstva klasa Volatile su, s druge strane, promjenjiva:

Class Task extends Volatile ( public function __construct() ( $this->data = new Threaded(); $this->data = new StdClass(); // valjano, budući da smo u nestabilnoj klasi)) $task = new class(new Task()) extends Thread ( public function __construct($vm) ( $this->volatileMember = $vm; var_dump($this->volatileMember->data); // object(stdClass)#4 (0) () // još uvijek nije valjano, budući da Volatile proširuje Threaded, tako da je svojstvo još uvijek Threaded član Threaded klase $this->volatileMember = new StdClass(); ) );

Možemo vidjeti da klasa Volatile nadjačava nepromjenjivost koju nameće nadređena klasa Threaded kako bi pružila mogućnost promjene svojstava Threaded (kao i unset()).

Postoji još jedan predmet rasprave koji pokriva temu varijabilnosti i klase Volatile - polja. U pthreads, nizovi se automatski pretvaraju u objekte Volatile kada se dodijele svojstvu klase Threaded. To je zato što jednostavno nije sigurno manipulirati nizom više PHP konteksta.

Pogledajmo ponovno primjer kako bismo bolje razumjeli neke stvari:

$niz = ; $task = new class($array) extends Thread (privatni $data; javna funkcija __construct(array $array) ( $this->data = $array; ) javna funkcija run() ( $this->data = 4; $ ovo->podaci = 5; print_r($ovo->podaci); ) ); $task->start() && $task->join(); /* Izlaz: Nestalni objekt ( => 1 => 2 => 3 => 4 => 5) */

Vidimo da se nestabilni objekti mogu tretirati kao da su nizovi jer podržavaju operacije niza kao što je (kao što je prikazano gore) operator subset(). Međutim, klase Volatile ne podržavaju osnovne funkcije polja kao što su array_pop i array_shift. Umjesto toga, klasa Threaded pruža nam takve operacije kao ugrađene metode.

Kao demonstracija:

$podaci = nova klasa proširuje Volatile ( public $a = 1; public $b = 2; public $c = 3; ); var_dump($podaci); var_dump($podaci->pop()); var_dump($data->shift()); var_dump($podaci); /* Izlaz: object(class@anonymous)#1 (3) ( ["a"]=> int(1) ["b"]=> int(2) ["c"]=> int(3) ) int(3) int(1) object(class@anonymous)#1 (1) ( ["b"]=> int(2) ) */

Druge podržane operacije uključuju Threaded::chunk i Threaded::merge .

Sinkronizacija

U posljednjem odjeljku ovog članka pogledat ćemo sinkronizaciju u pthreadovima. Sinkronizacija je metoda koja vam omogućuje kontrolu pristupa zajedničkim resursima.

Na primjer, implementirajmo jednostavan brojač:

$counter = nova klasa proširuje Thread ( public $i = 0; public function run() ( for ($i = 0; $i i; ) ) ); $counter->start(); za ($i = 0; $i i; ) $counter->join(); var_dump($counter->i); // ispisat će broj od 10 do 20

Bez upotrebe sinkronizacije, izlaz nije deterministički. Više niti piše u istu varijablu bez kontroliranog pristupa, što znači da će ažuriranja biti izgubljena.

Popravimo ovo tako da dobijemo točan izlaz od 20 dodavanjem vremena:

$counter = nova klasa proširuje Thread ( public $i = 0; public function run() ( $this->synchronized(function () ( for ($i = 0; $i i; ) )); ) ); $counter->start(); $brojač->sinkronizirano(funkcija ($brojač) ( za ($i = 0; $i i; ) ), $brojač); $counter->join(); var_dump($counter->i); // int(20)

Sinkronizirani blokovi koda također mogu međusobno komunicirati korištenjem metoda Threaded::wait i Threaded::notify (ili Threaded::notifyAll).

Ovdje je alternativno povećanje u dvije sinkronizirane while petlje:

$counter = nova klasa proširuje Thread ( public $cond = 1; javna funkcija run() ( $this->synchronized(function () ( for ($i = 0; $i notify(); if ($this->cond) === 1) ( $this->cond = 2; $this->wait(); ) ) )); ) ); $counter->start(); $counter->synchronized(function ($counter) ( if ($counter->cond !== 2) ( $counter->wait(); // čekaj da drugi počne prvi) for ($i = 10; $i obavijesti(); if ($counter->cond === 2) ( $counter->cond = 1; $counter->wait(); ) ) ), $counter); $counter->join(); /* Izlaz: 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) */

Možda ćete primijetiti dodatni uvjeti, koji su postavljeni oko poziva Threaded::wait . Ovi uvjeti su kritični jer dopuštaju nastavak sinkroniziranog povratnog poziva kada primi obavijest i navedeni uvjet je istinit. Ovo je važno jer obavijesti mogu dolaziti s drugih mjesta osim kada se poziva Threaded::notify. Dakle, ako pozivi Threaded::wait metode nisu bili zatvoreni u uvjetima, izvršit ćemo lažni pozivi buđenje, što će dovesti do nepredvidivog ponašanja koda.

Zaključak

Pogledali smo pet klasa paketa pthreads (Threaded, Thread, Worker, Volatile i Pool) i kako se svaka klasa koristi. Također smo pogledali novi koncept nepromjenjivosti u pthreads, made kratki osvrt podržane mogućnosti sinkronizacije. S ovim osnovama na mjestu, sada možemo početi gledati kako se pthreadovi mogu koristiti u slučajevima stvarnog svijeta! Ovo će biti tema našeg sljedećeg posta.

Ako vas zanima prijevod sljedeće objave, javite mi: komentirajte na društvenim mrežama. mrežama, glasujte i podijelite objavu s kolegama i prijateljima.

Nedavno sam isprobao pthreads i bio sam ugodno iznenađen - to je proširenje koje dodaje mogućnost rada s više pravih niti u PHP-u. Bez emulacije, bez magije, bez lažiranja - sve je stvarno.



Razmišljam o takvom zadatku. Postoji skup zadataka koje je potrebno brzo izvršiti. PHP ima druge alate za rješavanje ovog problema, oni nisu spomenuti ovdje, članak je o pthreads.



Što su pthreads

To je sve! Pa skoro sve. Zapravo, postoji nešto što bi znatiželjnog čitatelja moglo uznemiriti. Sve ovo ne radi standardni PHP, kompiliran sa zadanim opcijama. Da biste uživali u multithreadingu, morate imati omogućen ZTS (Zend Thread Safety) u vašem PHP-u.

PHP postava

Zatim, PHP sa ZTS-om. Ne obazirite se na veliku razliku u vremenu izvršavanja u usporedbi s PHP-om bez ZTS-a (37,65 naspram 265,05 sekundi), nisam pokušao generalizirati PHP postavke. U slučaju bez ZTS-a, imam omogućen XDebug na primjer.


Kao što vidite, kada se koriste 2 niti, brzina izvršavanja programa je otprilike 1,5 puta veća nego u slučaju linearnog koda. Kada koristite 4 niti - 3 puta.


Možete primijetiti da iako je procesor s 8 jezgri, vrijeme izvršenja programa ostalo je gotovo nepromijenjeno ako je korišteno više od 4 niti. Čini se da je to zbog činjenice da moj procesor ima 4 fizičke jezgre.Radi jasnoće, prikazao sam ploču u obliku dijagrama.


Sažetak

U PHP-u je moguće vrlo elegantno raditi s višenitnošću pomoću proširenja pthreads. To daje primjetan porast produktivnosti.

Oznake: Dodajte oznake

Pažnja! Ovaj je članak beznadno zastario ili ga autor sada procjenjuje kao informacijski beskoristan.

Ljepota open-source koda je njegova otvorenost :)) To jest. ako imate inteligencije/vremena/želje, možete točno shvatiti kako program radi. Loša strana takvog koda je poteškoća u dobivanju potrebnih kompiliranih paketa. Na primjer, PHP se može preuzeti kao izvorni kod za Nix sustave s naknadnom kompilacijom/sastavljanjem. Sve je već sastavljeno za Windows, ali ima puno gotovih binarnih paketa! Opcije s " nit sigurno/ne nit sigurno", VC6/VC9 I različite verzije sam PHP. Članak je stvoren da razjasni situaciju. Temelji se na različitim izvorima, dijelom na prijevodu s engleskog. Sve kako sljedeći put ne bih morao ponovno smišljati - "koja je svrha!?"

potrebno PHP verzija ovisi o verziji web poslužitelja na kojem će se koristiti. Na primjer, Apache 1.3.x radi s PHP verzijom 3.0.x, Apache 2.x radi s PHP verzijom 4.0 i novijim. Ali to nije toliki problem, fokusirajte se na novija stabilna izdanja i ono što hoster ima.

Kakve poštapalice VC6, VC9, VC11? PHP izvori za Windows kompajlirani su u Vizualni studio. VC9 se dobiva kada se kompajlira u VS 2008, VC11 - Visual Studio 2012. Sukladno tome, da bi vam cijela stvar radila, biblioteke moraju biti instalirane na vašem računalu Visual C++ za redistribuciju za Visual Studio odgovarajuću godinu. Malo pojašnjenja po ovom pitanju.

Osim toga, ako je vaš web poslužitelj stari Apache s apache.org, tada trebate preuzeti VC6 verziju PHP-a za čiju kompilaciju je korišten Visual Studio 6. Ako će PHP raditi za IIS ili u kombinaciji s novijim Apacheom , onda možete skupiti nešto modernije ;)

Meni je glavna prepreka u odabiru hoster. Sada postoji stabilna verzija PHP-a 5.5.4, ali on još uvijek ima 5.2.17!

Sada najzanimljiviji dio: " niti sigurno ili nije niti sigurno?"
Slobodan prijevod članka (Dominic Ryan, 27.09.2007.)

Nikada nisam vidio tako pokvareni engleski:((Htio sam brzo prevesti članak, ali imam poteškoća s razumijevanjem onoga što je autor napisao. Konstantni prijelazi između "što-je-to" i složenih rečenica općenito ističu Moskvu. Prijevod na Ruski je isto kompliciran činjenicom da nemam dovoljno znanja i mašte kako ispravno nazvati nešto na ruskom što je obično napisano samo na engleskom%) Na primjer, nikada nisam vidio tehnički koncept "višeprocesne arhitekture" na ruskom, ali moj biser je "protok-nesiguran" općenito je pitanje zdravog razuma. Općenito, reći ću vam što se dogodilo.

Razlika između niti sigurno I nije siguran za niti PHP binarni paketi

Otkako se PHP prvi put pojavio u sustavu Windows 20. listopada 2000. s PHP 3.0.17, njegovi su binarni paketi uvijek građeni kao niti sigurno (TS). Razlog je sljedeći: Windows koristi višenitnu arhitekturu, a Nix sustavi podržavaju višeprocesnu arhitekturu. Ako je PHP kompajliran kao višeprocesna CGI aplikacija umjesto multi-threaded aplikacije, onda njegova upotreba kao CGI modula pod Windowsima na IIS poslužitelju dovodi do ozbiljnog usporavanja i upotrebe CPU-a. S druge strane, možete povezati PHP s IIS-om kao ISAPI modul ( potrebna je višenitna izgradnja- cca. prevoditelj). Tada se javlja još jedan problem: neka popularna PHP proširenja dizajnirana su za Unix/Linux na umu, tj. s višeprocesnom arhitekturom, što dovodi do pada PHP-a spojenog na IIS kao ISAPI modul. Da. CGI kreiranje je najstabilnije okruženje za PHP na IIS-u s glavnim nedostatkom što je užasno sporo. Moramo učitati i rasteretiti cijelo PHP okruženje iz memorije svaki put kada postoji zahtjev.

U to je vrijeme postojalo nekoliko opcija za poboljšanje performansi PHP-a na IIS-u. Prvi je korištenje predmemoriranja opcodea s programima kao što je eAccelerator, koji pohranjuju PHP skripte u djelomično kompiliranom stanju na disku i/ili u memoriji. Ovaj pristup značajno smanjuje vrijeme izvršavanja skripte. Druga je mogućnost bila konfigurirati IIS za korištenje PHP-a u načinu rada FastCGI. U ovom slučaju, PHP proces se nije zatvorio nakon završetka, već je primio novi zadatak sa sljedećim PHP zahtjevom. Osim toga, bilo je moguće pokrenuti nekoliko PHP procesa u isto vrijeme, značajno ubrzavajući obradu zahtjeva, što je bio bonus PHP CGI moda. Međutim, možda je bilo manjih problema s kompatibilnošću s PHP ekstenzijama. Još uvijek je najviše brz način korištenje PHP-a, a instalacijski program “IIS Aid PHP Installer” konfiguriran je za postavljanje ove IIS konfiguracije.

Binarne datoteke prikupljene u način rada koji nije siguran za niti (nije siguran za niti, NTS), omogućuju vam da konfigurirate IIS (i druge web poslužitelje u sustavu Windows) da koriste PHP kao standardno CGI sučelje sa snažnim povećanjem performansi, jer u ovom slučaju (u takvoj verziji), PHP proces ne treba čekati da se niti sinkroniziraju. Kada se uspoređuju performanse PHP binarnih paketa "sigurnih niti" i "nesigurnih niti" na IIS-u kao standardnom CGI sučelju, povećanje performansi je do 40%, ali još uvijek nije tako brzo kao korištenje opcodea u FastCGI metodi . A najveći problem je što ne možete pouzdano koristiti binarne datoteke koje nisu sigurne za niti zajedno s onima koje su sigurne za niti. To znači da ne možete koristiti sustave za predmemoriju opcodea kao što je eAccelerator u PHP okruženju koje stvaraju binarni paketi nesigurni za niti (izjava koja je točna u vrijeme pisanja).

Ako se PHP koji nije siguran za niti ne može konfigurirati na istu brzinu kao okruženje sigurno za niti, zašto je onda potreban u takvoj izradi? Vratimo se na FastCGI i Microsoftov razvoj u ovom području u posljednjih nekoliko godina. Small-soft koderi stvorili su vlastitu verziju FastCGI-ja, koja vam omogućuje konfiguriranje PHP binarnih datoteka koje nisu sigurne za niti u FastCGI načinu rada, što donosi performanse brzinom svjetlosti :)

Iz članka sam zaključio da se kočnice promatraju samo kada se koriste s IIS web poslužiteljem. U svakom slučaju, pod Windows+Apache nisam vidio nikakve gluposti. Također piše da možete overclockati NTS sklop bilo koji web poslužitelj, ali ne mogu zamisliti takvu Apache konfiguraciju.