vitaszál php. A PHP verzió kiválasztása Windowshoz. A Jedi útja – a PCNTL kiterjesztéssel

02.04.2020 hírek

Jó barátom édesanyja elvesztette a bőröndjét a Szentpétervárról Moszkvába tartó járaton, és tovább utazott a meleg partokra, és most már az üdülőhelyen van - fürdőruha, szandál nélkül és egy pólóval. kézipoggyász. Régi emlékezetemből adtam neki egy-két tippet, hogy mit csináljon és hova fusson, és ma úgy döntöttem, hogy ide írok mindent, amit egy adott témában tudok.

Hogy elmagyarázzam, miért vagyok ilyen okos, hadd emlékeztessem önöket arra, hogy egy időben több légitársaság földi kiszolgálásában dolgoztam, többek között a poggyászok nyomon követésével kapcsolatos egyéni problémákkal is foglalkoztam. Nos, plusz természetesen a saját repülési tapasztalataid. Mivel azonban Évekkel ezelőtt otthagytam a légiközlekedési szolgáltatást, talán változhat néhány árnyalat - ha igen, akkor hálásan fogadom a témával kapcsolatos megjegyzéseket és javítom a bejegyzésben található információkat.

azzal kezdem mit kell tenned, hogy NE vesszen el poggyászod:
1. Tépje le a bőröndről a korábbi utazások összes címkéjét és matricáját, még a vonalkódos kicsiket is, amelyeket gyakran külön ragasztanak magára a bőröndre - zavaróak lehetnek automatikus rendszer poggyász szkennelése és válogatása.
2. Akasszon fel egy névtáblát a bőröndjére (táska, doboz, köteg - általában minden, amit felad a poggyászban) névcímkével: vásárolhat előre újrahasznosítható opciót, vagy vehet papírcímkét a bejelentkezési pultnál - általában minden többé-kevésbé tisztességes légitársaság korlátozás nélkül forgalmazza őket. És például az Emirates-nél általában kiváló műanyag címkék vannak egy tartós kábelen, amely nagyon sokáig bírja:

A régi paranoiások is úgy tudnak járni, mint én: mindig van a bőröndömön egy újrafelhasználható műanyag címke a Samsonite készletből, rajta az állandó lakcímem, telefonszámom és email, és ha elrepülök valahova nyaralni, ráakasztok egy papírt, amelyen feltüntetem az új helyen való tartózkodásom dátumait és az összes lehetséges elérhetőséget (a szálloda neve és címe, helyi telefonszáma, ha van, nos, természetesen a vezeték- és keresztnevem).
3. A check-in pultnál győződjön meg arról, hogy a poggyászcédula, amelyet a check-in ügyintéző kinyomtat, fel van-e ragasztva a poggyászára - a város kódjával, ahová repül, és a járatszámmal.
4. Ha több csatlakozó járata van, erről tájékoztassa a check-in ügynököt, és adja meg, hogy melyik pontig szeretné feladni poggyászát. Bizonyos esetekben a poggyászt az útvonal egyik vagy másik repülőterén kell felvenni, függetlenül az Ön kívánságától: ez vonatkozik például a repülőterek közötti transzferekre (Orly és Charles de Gaulle Párizsban, Domodedovo - Sheremetyevo) - " Vnukovo" Moszkvában), külön terminálok (1-es és 2-es terminál Frankfurtban) vagy az első érkezési ponton az USA-ban vagy Mexikóban - ez vámkövetelmény ezekben az országokban: tegyük fel, hogy Ön Moszkva-Washington-Phoenix, egy A poggyászcímkét minden három szakaszra kiállítják Phoenixbe, de Washingtonban a poggyászt fizikailag fel kell venni, át kell vámolni, és újra kell ellenőrizni. Továbbá, ha olyan babakocsit adnak fel, amelyet felvihettek a folyosóra, vagy egy állatot, valószínűleg át kell vennie egy tranzitponton. Általánosságban elmondható, hogy egy összetett, átszállással járó útvonal esetén jobb előre tisztázni a poggyászmozgások árnyalatait a légitársaság telefonos központjában, vagy extrém esetben a bejelentkezéskor.
5. Tegye láthatóvá csomagjait: nem mindig a mozgatók hibája vagy a válogatórendszer meghibásodása okozza a poggyász késését. Néha egy másik szórakozott utas, aki elfáradt egy hosszú repülés után, ugyanazt a fekete samsonitet vagy leírhatatlan táskát veszi ki a csomagtartóról, mint te. Ezért jelölje meg poggyászát: akasszon fel egy csomó fényes szalagot vagy egy kis puha játékot a fogantyúra, ragasszon rá egy nagy matricát, vagy egyszerűen részesítse előnyben a szokatlan színt a bőrönd kiválasztásának szakaszában.

Mit nem szabad feladni a poggyászban?
Ne feledje, hogy a poggyászt minden légitársaság és minden repülőtér elveszíti. Természetesen mindenkinél más a statisztika, de még a legmegbízhatóbb légitársaságok és a legkisebb repülőtér is elveszítheti vagy késleltetheti a poggyászt, ahol egyetlen rakodó szállítja a kocsit bőröndökkel közvetlenül a check-in pulttól a gépre. Ezért azt tanácsolom, hogy mindig vigye magával a kézipoggyászt:
- fontos dokumentumokat, beleértve azokat is, amelyekre nincs szükség a repülés során (például legutóbbi szentpétervári utam során jogosítványt kellett váltanom, és a házamban volt egy házassági anyakönyvi kivonat és mindenféle kártya egy autósiskolából kézipoggyász)
- kulcsok (a címét tartalmazó címkével kombinálva, ez veszélyes lehet)
- pénz, ékszerek (nem kommentár)
- drága, törékeny felszerelés
- rendszeresen szedett gyógyszereket a repüléshez szükséges mennyiségben, és kis tartalékkal arra az esetre, ha analógot kell keresnie egy idegen országban vagy városban. Vényköteles gyógyszereket, amelyeket a poggyász elvesztése esetén lehetetlen megvásárolni, vigye magával a teljes utazáshoz szükséges mennyiséget.
- valami, amire érkezéskor sürgősen szüksége lehet (pl. Töltő telefonhoz
- valami, aminek szentimentális értéke van az Ön számára: néha a poggyász örökre elveszik, és ha egy személyes napló elvesztése összetöri a szívét, jobb, ha otthon hagyja, vagy magával viszi a kabinba

Tanulságos történet: a szentpétervári Lufthansában végzett munkám során egy amerikai házaspár rohant be az irodánkba, kezét tördelve - nem volt náluk a poggyászuk, amiben nagyon fontos dokumentumok voltak az örökbefogadási perhez, a bíróság a következő nap. Természetesen a légitársaság a hibás a poggyász elvesztéséért, de kit érdekel? Az ilyen helyzetek elkerülésére elég volt a kézipoggyászba tenni a fontos papírokat.

Tehát megérkezett, és nem találta a csomagját a poggyászszalagon. Mit kell tenni?
1. Ha a hétköznapi bőröndökön kívül mást is bejelentkezett: síléc, cselló, teljes falú plazmaképernyő, babakocsi, élő márványkutya, ellenőrizze, hogy van-e külön átvételi pont az ún. túlméretezett poggyász vagy Bulky bagage - poggyász, hasonlóan a fent leírtakhoz, gyakran egy külön rekeszbe kerül, és manuálisan is külön rakod ki. Ha a poggyászát nem találja ott
2. Nyissa meg a Lost & Found vagy a Lost & Found pultot. Itt ki kell töltenie egy speciális űrlapot részletes információk poggyászáról: útiterv, kinézet, egy rövid tartalomlista, az állandó lakhelyen és az ideiglenes tartózkodáson lévő kapcsolataid. Ezenkívül a poggyászkövetési szolgáltatásban nagyobb valószínűséggel látja a következő poggyásztáblázatot:

Ennek az osztályozásnak megfelelően lesz kódolva az eltűnt poggyásza, és hogy megértse, ez a két bőrönd is ugyanúgy lesz kódolva:

Tehát nyugodtan írjon be további részleteket a leírásba, és ne hagyja ki a tartalom részt. Általános szabály, hogy a poggyászkésési jelentés első kitöltésekor (poggyászkésési jelentés) több olyan tartalom megjelölését kell kérni, amelyek alapján beazonosítható a poggyásza, ha nincs azonosító jel a külsején és a poggyászon. ki kell nyitni (ha a zacskót felbontják, akkor erre figyelmeztetik). Rossz példa: póló / könyv / nedves törlőkendők, jó példa: élénkpiros bikini / Malevich nyomtatott katalógus / összecsukható vas. A kérelem kitöltése után a poggyászkövető tiszt ad egy számot XXXYY11111 formátumban, ahol XXX az érkezési repülőtér kódja, YY az érkezési légitársaság kódja + a kérelem sorszámának 5 számjegye. : például JFKLH12345, ha a Lufthansával a New York-i Kennedy repülőtérre repült. Ne feledje vagy írja le ezt a számot – ez lesz a legegyszerűbb módja annak, hogy megtalálja jelentkezését további kérések esetén.
Ugyanezen a számon Ön is ellenőrizheti a keresett lista állapotát (valamiért elrepül a link: ha neked nem megy, akkor a Google World Tracer Online és szó szerint a második link - Baggage Tracing címmel a worldtracer.aero weboldalon - erre van szükséged), mert az átjutáshoz Az elveszett és megtalált megoldás gyakran nagyon nehéz
3. Próbáljon felvenni a kapcsolatot légitársasága irodájával az érkezési repülőtéren: néha (hangsúlyozom - NÉHA!), ha nem otthon, hanem ideiglenes tartózkodási helyre (nyaralás, üzleti út) érkezett, a légitársaság tud piperekészlet (a Lufthansa tartalmaz egy túlméretezett pólót, egy fogkefét és pasztát, egy hajkefét, kis csomag sampont és tusfürdőt, egy zacskó mosóport stb.), vagy fizessen be készpénzben kisebb kiadásokat spot (azonnali készpénzes fizetés).

Mi fog ezután történni?
A fájl (úgynevezett AHL) elküldésre kerül a központi poggyászkereső rendszerbe (World Tracer). Minden fel nem vett poggyász ugyanabba a keresőrendszerbe kerül, függetlenül attól, hogy címke nélkül találták meg a csomagtér zugaiban, vagy a poggyászszalagon maradtak, minden egyes tételhez létrejön egy XXXYY11111 formátumú fájl is, csak más alfajból - az ún. aktuális jelentés vagy OHD. Ha az AHL és az OHD fájl adatai megegyeznek (vezetéknév, bőrönd leírása, útvonal stb.), akkor mindkét állomás (ahol jelentették a poggyász elvesztését, és ahol a poggyászt fel nem vették) kap értesítést, majd a technológia kérdése: kettős ellenőrzés és siker esetén poggyász továbbítása a kívánt városba. Természetesen sok kézi munka is történik - üzenetküldés, hasonló, de nem azonos bőröndök elutasítása, plusz válaszadás többre telefonhívások- általában a poggyászkövető szolgálat munkatársai nem unatkoznak.
Hozzávetőleges statisztika: az elveszett poggyászok több mint 90%-a a keresés első 3 napjában megtalálható, 3%-a örökre elveszett.
Mit tudsz csinálni?
1. Ha megérkezéskor bármit meg kell vásárolnia, amire sürgősen szüksége van (fogkefétől az öltönyig), mindenképpen őrizze meg a nyugtákat a későbbi kártérítés érdekében. A szükségtelenül drága vásárlásokat azonban el kell hagyni, miért - később elmagyarázom.
2. A legutóbbi nyomok alapján készítsünk minél részletesebb tartalomlistát, lehetőleg színnel, márkával és hozzávetőleges költség minden dolog, ideális esetben bekapcsolva angol nyelv(mert ellenkező esetben a légitársaság alkalmazottjának le kell fordítania ezt a listát, hogy bekerüljön a rendszerbe), lépjen kapcsolatba a légitársasággal és küldje el nekik ezt a listát, ez hozzáadódik a poggyászkereső alkalmazáshoz. Az első 5 napban az érkezési repülőtér foglalkozik a poggyászkereséssel, majd a keresés átkerül a fuvarozó légitársasághoz (a jelentkezési számban feltüntetett légitársaság - emlékszel a JFKLH12345-re?), 21 nap elteltével pedig jelentkezhet a poggyászra. végső kompenzáció.
3. Ha a poggyász elvesztése iránti kérelem benyújtásától számított 21 napon belül nem találják meg, forduljon a fuvarozó légitársasághoz kártérítési igénnyel. Ha nem tévedek, az elévülési idő 2 év, i.e. Kártérítést a kárigényének benyújtásától számított két éven belül igényelhet.

Kártérítés kifizetése.
A kártérítés kifizetéséhez a légitársaság képviseletéhez kell fordulnia fizetési kérelemmel, a repülést és a poggyász elvesztésének tényét igazoló dokumentumokkal (beszállókártyák, poggyászcímkék, poggyászigénylő szám, fizetési adatok). Ha nem tévedek, az Orosz Föderációban a kártérítésről szóló határozatot 30 napon belül jogilag meg kell vizsgálni. Előfordulhat, hogy meg kell becsülni a tartalom költségét, és lehetőség szerint a bőrönd és a benne lévő dolgok vásárlásáról szóló bizonylatokat (megértem, hogy ez a legtöbb esetben nem reális, de ez az eljárás része).
Korábban a kifizetések a feladott poggyász súlya alapján történtek - körülbelül 20 dollár kilogrammonként. Később megváltozott az elszámolási rendszer, és a légitársaságok felelőssége 1000 hagyományos egységre korlátozódott (a hagyományos egység értékét a légitársaságon belül számolják), ami munkám idején hozzávetőlegesen 1300 eurónak felelt meg. Azok. hiába hozol egy csekket Louis Vuitton ezer bolíviai gekkóbőrből varrt, gyémántokkal kitömött bőröndjének megvásárlásához, 1300 eurónál többet nem kapsz.

Néha szükségessé válik több művelet egyidejű végrehajtása, például az egyik adatbázistábla módosításának ellenőrzése, és egy másik módosítás végrehajtása. Sőt, ha az egyik művelet (például a változások ellenőrzése) sokáig tart, nyilvánvaló, hogy a szekvenciális végrehajtás nem biztosítja az erőforrás-kiegyenlítést.

Az ilyen problémák megoldására a programozás többszálú feldolgozást használ - minden művelet külön szálba kerül, dedikált mennyiségű erőforrással, és azon belül működik. Ezzel a megközelítéssel minden feladatot külön-külön és függetlenül hajtanak végre.

Bár a PHP nem támogatja a többszálú feldolgozást, számos módszer létezik az emulációra, amelyekről az alábbiakban lesz szó.

1. A szkript több példányának futtatása – műveletenként egy példány

//woman.php if (!isset($_GET["szál"])) ( system("wget"http://localhost/woman.php?thread=make_me_happy"); system("wget>http: //localhost/ woman.php?thread=make_me_rich"); ) elseif ($_GET["szál"] == "make_me_happy") ( make_her_happy(); ) elseif ($_GET["szál"] == "make_me_rich" ) (keress_másik_egyet( ); )

Amikor ezt a szkriptet paraméterek nélkül futtatjuk, automatikusan elindítja saját két példányát, műveletazonosítókkal ("thread=make_me_happy" és "thread=make_me_rich"), amelyek elindítják a szükséges függvényeket.

Így elérjük a kívánt eredményt - két műveletet hajtunk végre egyszerre -, de ez természetesen nem többszálú, hanem egyszerűen mankó a feladatok egyidejű végrehajtásához.

2. A Jedi útvonala - a PCNTL kiterjesztéssel

A PCNTL egy olyan bővítmény, amely lehetővé teszi a folyamatokkal való teljes körű munkát. A kezelés mellett támogatja az üzenetek küldését, az állapotellenőrzést és a prioritások beállítását. Így néz ki az előző szkript PCNTL használatával:

$pid = pcntl_fork(); if ($pid == 0) ( make_her_happy(); ) elseif ($pid > 0) ( $pid2 = pcntl_fork(); if ($pid2 == 0) ( keres_másik_egyet(); ) )

Elég zavarosnak tűnik, haladjunk soronként.

Az első sorban "elágazzuk" az aktuális folyamatot (fork - a folyamat másolása az összes változó értékének mentéséből), felosztva két párhuzamosan futó folyamatra (aktuális és gyermek).

Hogy megértsük, hol vagyunk Ebben a pillanatban, egy utód- vagy szülőfolyamatban a pcntl_fork 0-t ad vissza az utódhoz, és a folyamatazonosítót a szülőhöz. Ezért a második sorban a $pid-t nézzük, ha nulla, akkor a gyermek folyamatban vagyunk - végrehajtjuk a függvényt, ellenkező esetben a szülőben vagyunk (4. sor), majd létrehozunk egy másik folyamatot és végrehajtjuk a feladatot ugyanúgy.

Szkript végrehajtási folyamat:

Így a szkript további 2 gyermekfolyamatot hoz létre, amelyek annak másolatai, ugyanazokat a változókat tartalmazzák hasonló értékkel. A pcntl_fork függvény által visszaadott azonosító segítségével pedig eligazítjuk, hogy éppen melyik folyamban vagyunk, és elvégezzük a szükséges műveleteket.

Úgy tűnik, hogy a PHP-fejlesztők ritkán használnak párhuzamosságot. Nem beszélek a szinkron kód egyszerűségéről, az egyszálú programozás természetesen egyszerűbb és áttekinthetőbb, de néha kevés használat a párhuzamosság mérhető teljesítménynövekedést hozhat.

Ebben a cikkben megvizsgáljuk, hogyan érhető el többszálas működés a PHP-ben a pthreads kiterjesztéssel. Ehhez telepíteni kell a PHP 7.x ZTS (Zend Thread Safety) verzióját telepített bővítmény pthreadsv3. (A cikk írásakor a PHP 7.1-ben a felhasználóknak a fő ágból kell telepíteniük a pthreads tárolóban – lásd a harmadik féltől származó kiterjesztést.)

Egy kis pontosítás: a pthreads v2 a PHP 5.x-hez való, és már nem támogatott, a pthreads v3 a PHP 7.x-hez való, és aktív fejlesztés alatt áll.

Egy ilyen kitérő után azonnal térjünk is a dologhoz!

Egyszeri feladatok kezelése

Néha az egyszeri feladatokat többszálas módon szeretné feldolgozni (például valamilyen I/O-kötött feladat végrehajtása). Ilyen esetekben használhatja a Thread osztályt új szál létrehozására, és egy külön szálon futtathat feldolgozást.

Például:

$task = új osztály kiterjeszti a szálat ( privát $válasz; public function run() ( $content = file_get_contents("http://google.com"); preg_match("~ (.+)~", $tartalom, $egyezések); $this->response = $egyezik; ) ); $task->start() && $task->join(); var_dump($task->response); // string (6) "Google"

Itt a futtatási módszer a mi feldolgozásunk, amelyet az új szálon belül hajtunk végre. A Thread::start meghívásakor egy új szál jön létre, és meghívódik a futtatási metódus. Ezután a létrehozott szálat visszakapcsoljuk a fő szálhoz a Thread::join meghívásával, amely blokkol, amíg a létrehozott szál be nem fejeződik. Ez biztosítja, hogy a feladat végrehajtása befejeződjön, mielőtt megpróbálnánk kiadni az eredményt (amely a $task->response mappában van tárolva).

Előfordulhat, hogy nem kívánatos egy osztályt a szállogikával kapcsolatos további felelősségekkel beszennyezni (beleértve a futási metódus meghatározásának felelősségét is). Az ilyen osztályokat a Threaded osztályból származtatva izolálhatjuk. Ezután egy másik szálon belül futtathatók:

Az osztályfeladat kiterjeszti a szálakat ( publikus $válasz; nyilvános függvény someWork() ( $content = file_get_contents("http://google.com"); preg_match("~ (.+) ~", $content, $matches); $ this->response = $egyezik; ) ) $task = new Task; $thread = new class($task) kiterjeszti Thread ( privát $feladat; public function __construct(Threaded $task) ( $this->task = $task; ) public function run() ( $this->task->someWork( ); ) ); $thread->start() && $thread->join(); var_dump($feladat->válasz);

Bármely osztály, amelyet külön szálon kell futtatni, kellörökölni a Threaded osztályból. Ennek az az oka, hogy biztosítja a szükséges képességeket a különböző szálakon történő feldolgozáshoz, valamint implicit biztonságot és hasznos interfészeket (például erőforrás-szinkronizálást).

Vessünk egy pillantást a pthreads kiterjesztés által biztosított osztályhierarchiára:

Menetes (átjárható, gyűjthető) Thread Worker Volatile Pool

A Thread és Threaded osztályok alapjait már ismertettük és megtanultuk, most nézzük meg a másik hármat (Worker , Volatile és Pool).

Szál újrafelhasználása

Egy új szál indítása minden párhuzamosítandó feladathoz meglehetősen költséges. Ennek az az oka, hogy a "nothing-common" architektúrát pthread-ben kell megvalósítani, hogy a PHP-n belül többszálú legyen. Ez azt jelenti, hogy a PHP értelmező aktuális példányának teljes végrehajtási környezetét (beleértve minden osztályt, interfészt, tulajdonságot és függvényt) át kell másolni minden létrehozott szálhoz. Mivel ennek észrevehető hatása van a teljesítményre, a szálat mindig újra fel kell használni, amikor csak lehetséges. A szálak kétféleképpen használhatók fel újra: a Worker s vagy a Pool s segítségével.

A Worker osztály egy másik szálon belüli feladatok szinkron végrehajtására szolgál. Ez úgy történik, hogy létrehozza a Worker új példányát (ami új szálat hoz létre), majd a feladatokat az adott szál veremébe helyezi (a Worker::stack használatával).

Íme egy kis példa:

Az osztályfeladat kiterjeszti a szálakat ( privát $érték; nyilvános függvény __construct(int $i) ( $this->value = $i; ) public function run() ( usleep(250000); echo "Task: ($this->value) \n"; ) ) $dolgozó = new Dolgozó(); $dolgozó->start(); for ($i = 0; $i verem(new Task($i)); ) while ($worker->collect()); $dolgozó->leállítás();

A fenti példában 15 feladat kerül a verembe egy új $worker objektumhoz a Worker::stack metóduson keresztül, majd azokat a leküldés sorrendjében dolgozza fel. A fent látható Worker::collect metódus a feladatok megtisztítására szolgál, amint azok végrehajtása befejeződött. Ezzel a while cikluson belül blokkoljuk a főszálat mindaddig, amíg a veremben lévő összes feladat be nem fejeződik, és amíg ki nem törlődnek - mielőtt a Worker::shutdownt hívnánk. Egy dolgozó korai leállítása (azaz amíg vannak még elvégzendő feladatok) továbbra is blokkolja a fő szálat, amíg az összes feladat be nem fejezi a végrehajtását, csak a feladatokat nem gyűjtik össze (amely memóriaszivárgással jár).

A Worker osztály számos más metódust is kínál a feladatveremhez, beleértve a Worker::unstack-et az utoljára beillesztett feladat eltávolításához, és a Worker::getStacked-et a végrehajtási veremben lévő feladatok számának lekéréséhez. A dolgozó verem csak azokat a feladatokat tartalmazza, amelyeket végre kell hajtani. Ha egy feladat a veremben elkészült, azt eltávolítjuk, és egy külön (belső) verembe helyezzük szemétgyűjtés céljából (a Worker::collect módszerrel).

A szálak sok feladathoz való újrafelhasználásának másik módja a szálkészlet használata (a Pool osztályon keresztül). A szálkészlet dolgozók csoportját használja a feladatok futtatásának engedélyezéséhez egyidejűleg, amelyben az egyidejűségi tényező (az általa futtatott készletszálak száma) a készlet létrehozásakor van beállítva.

Alkalmazzuk a fenti példát a dolgozók csoportjának használatához:

Az osztályfeladat kiterjeszti a szálakat ( privát $érték; nyilvános függvény __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();

Van néhány figyelemreméltó különbség a pool és a dolgozó használatakor. Először is, a készletet nem kell manuálisan elindítani, azonnal megkezdi a feladatok végrehajtását, amint elérhetővé válnak. Másodszor, mi Küld feladatokat a medencéhez, nem rakd fel őket egy veremre. Ezenkívül a Pool osztály nem örökli a Threaded-től, ezért nem adható át más szálaknak (ellentétben a Workerrel).

A bevált gyakorlat szerint a dolgozóknak és a csoportoknak mindig azonnal meg kell tisztítaniuk a feladataikat, amint befejezték, majd saját maguknak kell leállítaniuk a feladataikat. A Thread osztállyal létrehozott szálakat is csatolni kell a szülőszálhoz.

pszálak és (nem) mutabilitás

Az utolsó osztály, amelyet érinteni fogunk, a Volatile , a pthreads v3 új kiegészítése. A változtathatatlanság fogalma fontos fogalommá vált a pthread-ekben, mivel enélkül a teljesítmény jelentősen csökken. Ezért alapértelmezés szerint a Threaded osztályok tulajdonságai, amelyek maguk is Threaded objektumok, immár megváltoztathatatlanok, ezért nem írhatók felül az eredeti hozzárendelésük után. Az ilyen tulajdonságok explicit mutációja jelenleg előnyben részesített, és továbbra is elérhető az új Volatile osztállyal.

Vessünk egy példát, amely bemutatja az új megváltoztathatatlansági korlátokat:

Az osztályfeladat kiterjeszti a Threaded // a Threaded osztályt ( nyilvános függvény __construct() ( $this->data = new Threaded(); // A $this->data nem írható felül, mivel egy szálas osztály Threaded tulajdonsága) ) $task = new class(new Task()) kiterjeszti a szálat ( // egy szálas osztály, mivel a szál kiterjeszti a szálas nyilvános függvényt __construct($tm) ( $this->threadedMember = $tm; var_dump($this->threadedMember-> data); // object(Threaded)#3 (0) () $this->threadedMember = new StdClass(); // érvénytelen, mivel a tulajdonság egy szálas osztály Threaded tagja ) );

A Volatile osztályok Threaded tulajdonságai viszont változtathatók:

Az osztályfeladat kiterjeszti a Volatile-t ( nyilvános függvény __construct() ( $this->data = new Threaded(); $this->data = new StdClass(); // érvényes, mivel volatile osztályban vagyunk ) ) $task = new class(new Task()) kiterjeszti a szálat ( nyilvános függvény __construct($vm) ( $this->volatileMember = $vm; var_dump($this->volatileMember->data); // object(stdClass)#4 (0) () // továbbra is érvénytelen, mivel a Volatile kiterjeszti a Threaded-et, tehát a tulajdonság még mindig egy Threaded osztály Threaded tagja $this->volatileMember = new StdClass(); ) );

Látjuk, hogy a Volatile osztály felülírja a Threaded szülőosztály által előírt megváltoztathatatlanságot, hogy lehetővé tegye a Threaded tulajdonságok (valamint az unset() ) megváltoztatását.

Van még egy téma, amelyet meg kell vitatni, hogy lefedjük a mutabilitás és a volatile osztály témakörét - tömbök. A pthreadekben a tömbök automatikusan átkerülnek a volatile objektumokhoz, ha a Threaded osztály egy tulajdonságához vannak hozzárendelve. Ennek az az oka, hogy egyszerűen nem biztonságos egy tömböt több PHP kontextusból manipulálni.

Nézzük újra a példát, hogy jobban megértsünk néhány dolgot:

$tömb = ; $task = new class($tömb) kiterjeszti Thread ( privát $adat; nyilvános függvény __construct(array $tömb) ( $this->data = $tömb; ) public function run() ( $this->data = 4; $ this->data = 5; print_r($this->data); ) ); $feladat->start() && $feladat->join(); /* Kimenet: illékony objektum ( => 1 => 2 => 3 => 4 => 5) */

Látjuk, hogy az illékony objektumokat úgy lehet kezelni, mintha tömbök lennének, mivel támogatják a tömbműveleteket, például (ahogy fentebb látható) az alhalmaz operátora (). A Volatile osztályok azonban nem támogatják az olyan alapvető tömbfüggvényeket, mint az array_pop és az array_shift . Ehelyett a Threaded osztály a beépített metódusokhoz hasonló műveleteket biztosít számunkra.

Demóként:

$adat = új osztály kiterjeszti Volatile ( nyilvános $a = 1; nyilvános $b = 2; nyilvános $c = 3; ); var_dump($adat); var_dump($adat->pop()); var_dump($adat->shift()); var_dump($adat); /* Kimenet: object( [e-mail védett])#1 (3) ( ["a"]=> int(1) ["b"]=> int(2) ["c"]=> int(3) ) int(3) int(1) objektum ( [e-mail védett])#1 (1) ( ["b"]=> int(2) ) */

Egyéb támogatott műveletek közé tartozik a Threaded::chunk és a Threaded::merge .

Szinkronizálás

A cikk utolsó részében a pthread-ekben történő szinkronizálást nézzük meg. A szinkronizálás egy olyan módszer, amely lehetővé teszi a megosztott erőforrásokhoz való hozzáférés szabályozását.

Például valósítsunk meg egy egyszerű számlálót:

$számláló = új osztály kiterjeszti a szálat ( public $i = 0; public function run() ( for ($i = 0; $i i; ) ) ); $számláló->start(); for ($i = 0; $i i; ) $counter->join(); var_dump($számláló->i); // kiír egy számot 10-től 20-ig

Szinkronizálás nélkül a kimenet nem determinisztikus. Több szál ír ugyanarra a változóra ellenőrzött hozzáférés nélkül, ami azt jelenti, hogy a frissítések elvesznek.

Javítsuk ki, hogy a megfelelő 20-as kimenetet kapjuk egy szinkronizálás hozzáadásával:

$számláló = new class kiterjeszti Thread ( public $i = 0; public function run() ( $this->synchronized(function () ( for ($i = 0; $i i; ) )); ) ); $számláló->start(); $számláló->szinkronizált(függvény ($számláló) ( for ($i = 0; $i i; ) ), $számláló); $counter->join(); var_dump($számláló->i); // int(20)

A szinkronizált kódblokkok egymással is kommunikálhatnak a Threaded::wait és Threaded::notify (vagy Threaded::notifyAll) metódusokkal.

Itt van egy alternatív növekmény két szinkronizált while ciklusban:

$számláló = új osztály kiterjeszti Thread ( public $cond = 1; public function run() ( $this->synchronized(function ()) ( for ($i = 0; $i notify();); if ($this->cond === 1) ( $this->cond = 2; $this->wait(); ) ) )); ) ); $számláló->start(); $counter->synchronized(function ($counter) ( if ($counter->cond !== 2) ( $counter->wait(); // várja meg, míg a másik indul először ) for ($i = 10; $i notify(); if ($counter->cond === 2) ( $counter->cond = 1; $counter->wait(); ) ) ), $counter); $counter->join(); /* Kimenet: 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) */

Észreveheti további feltételek, amelyek a Threaded::wait hívás köré kerültek. Ezek a feltételek kritikusak , mert lehetővé teszik a szinkronizált visszahívás folytatását , ha értesítést kapott , és a megadott feltétel igaz . Ez azért fontos, mert az értesítések más helyekről is érkezhetnek, mint a Threaded::notify meghívásakor. Így, ha a Threaded::wait metódus hívásai nem lennének feltételekkel csomagolva, akkor végrehajtanánk hamis hívásokébredés, ami kiszámíthatatlan kódviselkedéshez vezet.

Következtetés

Megnéztük a pthreads csomag öt osztályát (Threaded , Thread , Worker , Volatile és Pool), és az egyes osztályok használatát. Vettünk egy pillantást a megváltoztathatatlanság új koncepciójára is a pthread-ekben rövid áttekintés támogatott szinkronizálási lehetőségek. Ha ezekkel az alapokkal a helyükön van, elkezdhetjük megvizsgálni, hogyan lehet pthread-eket használni valós esetekben! Ez lesz a következő bejegyzésünk témája.

Ha érdekel a következő bejegyzés fordítása, jelezd: kommenteld a közösségi oldalon. hálózatokon, szavazzon pozitívan, és ossza meg a bejegyzést kollégáival és barátaival.

Nemrég kipróbáltam a pthread-eket, és kellemesen meglepődtem – ez egy olyan kiterjesztés, amely több valódi szállal való együttműködés lehetőségét is hozzáadja a PHP-hez. Nincs emuláció, nincs varázslat, nincs hamisítvány – minden valódi.



Ezt a kérdést vizsgálom. Van egy csomó feladat, amelyeket gyorsan kell elvégezni. A PHP-nek más eszközei is vannak a probléma megoldására, ezekről itt nincs szó, a cikk pthreadekről szól.



Mi az a pthreads

Ez minden! Nos, szinte mindent. Valójában van valami, ami felzaklathatja a kíváncsi olvasót. Mindez nem működik szabványos PHP alapértelmezett opciókkal összeállítva. A többszálú használat élvezetéhez engedélyeznie kell a ZTS-t (Zend Thread Safety) a PHP-ben.

PHP beállítás

Ezután PHP ZTS-sel. Figyelmen kívül hagyjuk a végrehajtási idő ilyen nagy különbségét a ZTS nélküli PHP-hez képest (37,65 vs 265,05 másodperc), nem próbáltam általánosítani a PHP beállítását. ZTS nélküli esetben például engedélyeztem az XDebug-ot.


Amint láthatja, 2 szál használatakor a program végrehajtási sebessége körülbelül 1,5-szer nagyobb, mint egy lineáris kód esetében. 4 szál használata esetén - 3 alkalommal.


Észrevehető, hogy bár a processzor 8 magos, a program végrehajtási ideje szinte nem változott, ha 4-nél több szálat használtak. Úgy tűnik, ez annak köszönhető, hogy a processzorom 4 fizikai maggal rendelkezik.Az érthetőség kedvéért egy táblát ábrázoltam diagram formájában.


Összegzés

A PHP meglehetősen elegáns többszálas kezelést tesz lehetővé a pthread kiterjesztéssel. Ez észrevehető teljesítménynövekedést ad.

Címkék: Címkék hozzáadása

Figyelem! Ez a cikk reménytelenül elavult, vagy a szerző úgy értékelte, hogy nincs információs értéke.

A nyílt forráskód szépsége a nyitottsága :)) I.e. ha van eszed / időd / vágyad, kitalálhatod, hogy pontosan hogyan működik a program. Az ilyen kód hátránya a megfelelő összeállítású csomagok beszerzésének nehézsége. Például a PHP letölthető forrásként a Nix rendszerek számára, majd lefordítható/építhető. Windowsra már minden fel van építve, de sok kész bináris csomag létezik! Opciók a " menetbiztos/nem menetbiztos", VC6/VC9És különböző verziók maga a PHP. A cikk a helyzet tisztázására készült. Különböző forrásokon alapul, részben - angol nyelvű fordításon. Mindezt azért, hogy legközelebb ne kelljen újra rájönnöm - „mi értelme!?”.

Szükséges PHP verzió a webszerver verziójától függ, amelyen használni fogják. Például az Apache 1.3.x a PHP 3.0.x verziójával működik, az Apache 2.x pedig a PHP 4.0 és újabb verziójával. De ez nem akkora probléma, koncentrálj az újabb stabil kiadásokra, és arra, hogy mennyibe kerül a hoster.

Mik az előfizetések VC6, VC9, VC11? A Windows alatti PHP-források erre vannak fordítva vizuális Stúdió. A VC9-et a VS 2008, VC11 - Visual Studio 2012 programban történő fordításkor kapjuk meg. Ennek megfelelően ahhoz, hogy ez az egész működjön, könyvtárakat kell telepíteni a számítógépére Visual C++ újraterjeszthető a Visual Studio számára a megfelelő év. Egy kis pontosítás ezzel kapcsolatban.

Ezen túlmenően, ha egy régi Apache az apache.org webhelyről a webszerver, akkor le kell töltenie a PHP VC6-os verzióit, amelyeket a Visual Studio 6 segítségével fordítottak le. Ha a PHP működik az IIS-hez vagy az újabb Apache-hoz , akkor össze lehet rakni valami modernebbet ;)

Számomra a fő kábulat a választásban a házigazda. Most van a PHP 5.5.4 stabil verziója, és még mindig az 5.2.17!

Most a legérdekesebb rész: cérnabiztos vagy nem szál biztonságos?"
A cikk ingyenes fordítása (Dominic Ryan, 2007.09.27.)

Ilyen törött angolt még nem láttam :((Gyorsan le akartam fordítani a cikket, de alig értem, mit írt a szerző. Az állandó átmenet a "mi-az" és az összetett mondatok között általában kibírja Moszkvát. Az oroszra fordítás is bonyolítja az a tény, hogy nincs elég tudásom és fantáziám, hogyan kell helyesen elnevezni valamit oroszul, amit általában csak angolul írnak le.%) Például soha nem láttam a "többfolyamatos architektúra" technikai fogalmát oroszul, ill. az én gyöngyöm "áram nem biztonságos" általában józan ész kérdése.Általában mi történt, azt hozom.

A különbség köztük cérnabiztosÉs nem szál biztonságos PHP bináris csomagok

Amióta a PHP először 2000. október 20-án jelent meg Windowson a PHP 3.0.17-ben, bináris csomagjait mindig is menetbiztos (TS). Az indoklás a következő: a Windows többszálú munkaarchitektúrát használ, míg a Nix rendszerek támogatják a többfolyamatos architektúrát. Ha a PHP-t többfolyamatos CGI-alkalmazásként fordították többszálas helyett, akkor a CGI-modulként való használata Windows alatt egy IIS-kiszolgálón komoly késést és CPU-használatot eredményez. Másrészt a PHP-t csatlakoztathatja az IIS-hez ISAPI modulként ( többszálas build szükséges- kb. fordító). Aztán újabb probléma adódik: néhány népszerű PHP-bővítményt a Unix/Linux szem előtt tartásával terveznek, pl. többfolyamatos architektúrával, ami az IIS-hez ISAPI-modulként csatlakoztatott PHP összeomlásához vezet. Hogy. A CGI-készítés a PHP legstabilabb környezete IIS-en, azzal a fő hátrányával, hogy rettenetesen lassú. Minden alkalommal be kell tölteni és ki kell tölteni a teljes PHP környezetet a memóriából, amikor egy kérés érkezik.

Abban az időben számos lehetőség volt a PHP teljesítményének javítására IIS-en. Az első az olyan programok, mint például az eAccelerator, opcode-gyorsítótár használata, amelyek a PHP-szkripteket részben lefordított állapotban mentik a lemezre és/vagy a memóriába. Ez a megközelítés jelentősen csökkenti a szkript végrehajtási idejét. Egy másik lehetőség volt az IIS beállítása a PHP módban való használatára FastCGI. Ugyanakkor a PHP folyamat feldolgozás után nem zárt be, hanem a következő php kéréssel új feladatot kapott. Ezen kívül lehetőség nyílt több PHP folyamat egyidejű futtatására, ami jelentősen felgyorsította a kérések feldolgozását, ami a PHP CGI módjának bónusza volt. Azonban előfordulhatnak kisebb kompatibilitási problémák a PHP-kiterjesztésekkel. Még mindig ez a legtöbb gyors út PHP használatával, és pontosan erre van beállítva az IIS Aid PHP Installer.

ben összeállított binárisok szál nem biztonságos mód (nem szál biztonságos, NTS), lehetővé teszi az IIS (és más webszerverek Windows alatti) konfigurálását úgy, hogy a PHP szabványos CGI interfészként használhassa, hatalmas teljesítménynövekedéssel, mivel ebben az esetben (egy ilyen buildben) a PHP folyamatnak nem kell megvárnia a szálak szinkronizálását. Ha összehasonlítjuk a "szálbiztos" és a "szálmentes" PHP bináris csomagokat az IIS-en szabványos CGI-felületként, a teljesítménynövekedés akár 40%-ot is elérhet, de még mindig nem olyan gyors, mint a FastCGI metódusban az opcode használata. A legnagyobb probléma pedig az, hogy nem lehet következetesen használni a szálbiztos binárisokat a szálbiztos binárisokkal együtt. Ez azt jelenti, hogy nem használhat eAccelerator típusú műveleti kód gyorsítótárazási rendszereket olyan PHP-környezetben, amelyet nem biztonságos bináris csomagok hoztak létre (ez az állítás az írás idején igaz).

Ha a szálbiztos PHP-t nem lehet olyan gyorsra állítani, mint a szálbiztos PHP-t, akkor miért van rá szükség egy ilyen buildben? Térjünk vissza a FastCGI-hez és a Microsoft ezen a területen az elmúlt néhány évben végzett fejlesztéseihez. A lágy kódolók elkészítették a FastCGI saját verzióját, amely lehetővé teszi a nem biztonságos PHP binárisok konfigurálását FastCGI módban, ami fénysebességgel hozza a teljesítményt :)

A cikkből arra a következtetésre jutottam, hogy a fékeket csak az IIS webszerverrel használva figyelik meg. Amúgy Windows+Apache alatt nem láttam tupnyakovot. Azt is mondja, hogy az NTS-összeállítást túl lehet hajtani Bármi webszerver, de ilyen Apache konfigot nem tudok elképzelni.