От какви действия, извършени в пияно състояние, много се срамувате? Резултати от теста за ефективност при панически разстройства

СЪРДЕЧНА НЕВРОЗА (КАРДИОФОБИЯ). Специална форма на фобия, наред с паническия синдром, е кардиофобията, която трябва да бъде описана специално поради характерната си клинична картина и значителна честота. Среща се предимно при млади хора, по-често при мъже, а също и при деца.

Пароксизмална състояния на тревожност, при които пациентите се страхуват, че сърцето ще спре да работи и ще умре, може да протече и без наличие на соматично заболяване. В началото на следващия пристъп се появяват гадене, замаяност, вътрешно безпокойство и леко притискане на сърцето.

Въпреки това, в много случаи, без никакво предупреждение, възниква тежка атака: сърцебиенеусеща се в цялото тяло, известно увеличение кръвно налягане, силно усещане за притискане и стягане в областта на сърцето, липса на въздух, изпотяване, световъртеж и чувство на припадък (но не и загуба на съзнание), треперене в цялото тяло и основен страх. Пациентът вярва, че сърцето му ще спре за секунда и той ще падне мъртъв. Това е страхът от самоунищожение и смърт. При силно вълнениеболните тичат и молят за помощ. Ако се появи атака на страх по време на пътуване в кола, пациентът е принуден да спре и да си почине.

След първата атака настъпва фобийно развитие. Пациентите губят психическото си равновесие, живеят в постоянен страх, чакат следващия пристъп или смърт, изпитват страх от страх (страх от очакване, фобия). В същото време не им помага посланието на терапевта за нормални показателисърдечна функция, нито убеждаване, че предишни атаки нямат последствия. Честотата на пристъпите и интервалите между тях са неравномерни. На интервали пациентът внимателно следи сърдечните си функции, контролира пулса и записва най-малките му отклонения. Той възприема случайните екстрасистоли като безспорни признаци на заболяване с безнадежден изход.

Пациентите наблюдават с повишено внимание други вегетативни прояви, както и леки колебания в тяхното благосъстояние. Пациентите се грижат за себе си, трудно се осмеляват да ходят, стремят се да елиминират всеки стрес, тревоги и на първо място трудни ситуации, за да предотвратят атака (уклончиво поведение). Вместо страха от смъртта в много случаи все по-често се появява страхът от страх и от страхови ситуации.

УСЛОВИЯ НА ПОЯВА. Причината за първата кардиофобична атака често е остър конфликт и пренапрежение, раздяла и разочарование, ситуация на самота и изоставяне, както и безпокойство в случай на сърдечна смърт на близък човек.

Знаейки, че винаги може да настъпи сърдечна смърт, дори при млади и здрави, се превръща в тревожен фактор. Интензивната консумация на кафе и никотин може да предизвика този процес. Началото често идва от детството. Засегнати са предимно разглезени и зависими деца, с подчертана зависимост от майката, до голяма степен с амбивалентни нагласи: очакване на любов, от една страна, и желание за независимост с агресивни импулси, от друга, с противоречиви фантазии за привързаност и раздяла. Такива нагласи са особено опасни, когато връзките са прекъснати, настъпят раздяли и разочарования. Кардиофобът често живее в страх от раздяла, преди да осъзнае, че я иска и се страхува от нея. Редовно възникват съвместни проблеми с родителите и конфликти с партньори.

ЛЕЧЕНИЕ
Ако в остро състояниеприсъствието на лекар и разговор с него не предизвикват подобрение, показани са транквиланти или бета-блокери. Подобно на други пациенти с неврози със страх, много фобици се опитват да се самолекуват с алкохол; но ефектът му е недостатъчен, а опасността от алкохолна зависимост е голяма. Фармакотерапията е само спомагателно средство, предимно в остри случаи, както и първоначално ефективно средство за защита.

Психотерапията е решаваща. Колкото по-рано започне, толкова по-добре. Проучване на причините и конфликтни ситуацииведнага след първите кардиофобични атаки може да спре последващото развитие на фобия. По-късното лечение е по-трудно и се налага продължителна психотерапия.

За тези и други тревожни разстройства е особено показана поведенческа терапия (конфронтация при възбуждане, когнитивна терапия, обучение на самочувствие). Отличителна черта на обучението за избягване на тревожност е, че то работи върху модел на десенсибилизация (към съответните условия на ежедневните ситуации), а обучението за управление на тревожността използва принудително потапяне във фобична ситуация (наводнение) и формиране на стратегии за справяне. При тежки тревожни разстройства е необходимо провеждането клинично лечениеизползване на различни модели на психотерапия.


02.10.2011, 21:27

За това, че наби един пич и му закачи тениската на едно дърво.И тя гони тъпака няколко километра сама и когато падна, тя започна да го пикае.Но те си го заслужиха.

В голяма компания досадих на едно момиче и казах, че приятелят й я е купил на разпродажба и също яде банани и слага корите в скута на всички в микробуса, а също така постоянно организирам лесбийски шоута в баровете, веднъж погледнах под полите на сервитьорките във ВИП клуб и раздаваше коментари, но като цяло аз съм много пиян веднага забравям, че обичам хората да казват, ако се събудиш и те е срам, но не помня защо точно за мен

След последното пиянство ми писна:
1. изкрещя от балкона на момчето „смучи ме“
2. изял цигара
3. хвърляше ябълки
4. Обадих се на човека и му казах, че няма да му правя секс по груб начин
5. удавени бикове в сок от грейпфрут
6. обади се на майка ми и ми каза, че съм трезвен
7. Помолих гаджето на моя приятел да ни донесе вино.
8. Изпиках се покрай тоалетната, тъй като бяха 2 - избрах грешната и паднах
9. падна от банята

Веднъж тичах из апартамента с нож след съпруга си, въпреки че изпих няколко чаши шампанско. На другата сутрин ме хвана страх - ами ако го ударя с нож, но просто реших да го уплаша. И не знам защо получих такъв ритник!

Винаги е едно и също, като като се напия отивам в парка да търся дрънкаджии да им се подигравам, или създавам тези теми във форума... сутрин си мисля, глупава ли съм?...

Веднъж едно момче ме удряше и аз бях толкова пиян, че започнах да му обяснявам популярно, че нищо няма да се обърка, защото съм „Кървавата Мери“ (те бяха) и този прякор толкова много ми влезе в душата, че почти извиках на всички, които срещнах: „Аз съм Блъди Мери“, за щастие не беше в родния ми град

-* обадих се на бившия ми, изразих всичко, което мисля за него
*обади се любимият ми, каза колко много го искам
*яде шаурма с фолио
* ругаех едно момче, което срещнах в клуб, въпреки че ми помогна и ми донесе вода
*танцува стриптийз в клуб на състезание, взе второ място
*хвърли лед по непознат
*приятелят на моя човек кара жълт Hummer. Никога не съм виждал нещо подобно в Корея. когато всички отидохме на купона заедно. Наведох се от колата на моя човек и, сочейки Hummer-а, който караше отпред, изкрещях, че тази кола е мой приятел
*вчера бях в клуба. когато се прибирах с такси сутринта, казах на шофьора: [превод от корейски. дословно!] „Храната, която изядох, току-що ми каза, че иска да излезе!“
*Имам и приятел монголец. Качих се на гърба му, принудих го да ме носи на гърба си и изкрещях на цялата улица, че той е моят монголски кон
но като цяло имаше много повече, няма да си спомняте...

Писах на момчето в 4 часа сутринта " Лека нощ, скъпо"

С приятелите ми се напихме с коняк, всички се прибраха, а аз глупаво извиках такси (беше 3 сутринта) и отидох да видя бившия си приятел, с когото се разделихме преди 4 месеца (останахме приятели). не помня как влязох във входа, стигнах до апартамента му, започнах да му разбивам вратата и да викам "ЖЕНИ СЕ ЗА МЕН МАРАТ", той, горкият, полудя. Завлече ме вкъщи и под студен душ, даде ми силен чай .. След два часа си тръгнах и тогава, когато разбрах какво съм направила, НАИСТИНА МЕ Е СРАМ.След това се помирихме и още сме заедно. След това не пия повече чаша шампанско.


...

02.10.2011, 22:09

Убитата жена се разхождаше с един човек през градината и тогава ми се стори, че той някак си ме обиди, като вървеше на няколко крачки пред мен, а не до мен. Обидих се и се качих на едно дърво, но той дори не забеляза... тичаше из градината час и половина да ме търси... и аз спокойно припаднах на дървото и спах до сутринта. ...
...
Но на сутринта не можах веднага да си спомня как се озовах на клоните. По дяволите, как беше след това
;Д;Д;Д

Интерпретация

02.10.2011, 22:42

Срамувам се от определени действия, извършени в трезво състояние :) Но това е по-близо до философията. Докато бях пиян... много неща бяха забавни, смущаващи... не, съжалявам)))))

Елена Лотус

02.10.2011, 23:17

Вчера, след като разбрах, че телефонът ми (ООО!!!) вече не е мой, се напих.здраво.и (който ме познава, да не казва, че пия като мишка) тогава направих нещо...това само на близки приятели, общо взето тайна и тогава ще мисля на кого да кажа... Ресторант Паберти пак беше шокиран. Сега разглеждам галерията със снимки с надеждата да видя какво се е случило: (но аз Не ме е срам... не... Просто си мислех, че съм свестен.

02.10.2011, 23:31

;Д;Д;Д
Винаги съм твърдял, че лелите не трябва да пият!!! ВСЕКИ!!!;)

..;D;D;D казваш истината

02.10.2011, 23:36

Пияната жена е като китайско пухено яке: меко и пасва.
Галигин

Елена Лотус

02.10.2011, 23:41

Но мъжете харесват да? Всеки може да пие. и лели и чичовци...само трябва да внимавате...днес не ви боли главата...боли ви душата...ще пиете ли нещо?Това е просто омагьосан кръг;)

03.10.2011, 00:15

Пийте какво ли не докато сте млади и здрави :)

03.10.2011, 01:48

избирателно крадени от женския форум :)

Едва не се изпиках в коша за пране пред майка ми..... объркана с тоалетната.... опа....

Убитата жена се разхождаше с един човек през градината и тогава ми се стори, че той някак си ме обиди, като вървеше на няколко крачки пред мен, а не до мен. Обидих се и се качих на едно дърво, но той дори не забеляза... тичаше из градината час и половина да ме търси... и аз спокойно припаднах на дървото и спах до сутринта. ...
...
Но на сутринта не можах веднага да си спомня как се озовах на клоните. По дяволите, как беше след това

На балкона имаше легени и саксии, където майка ми отглеждаше лук. Аз "слабо" пиках във всяка от тези саксии =((((в собствените си легла ((разбира се, че няма да кажа на майка ми, хвърли всичко по дяволите) боклука,тук съм реших да ти пикая зелените!Ами продължи да расте,после отиде в салатата

03.10.2011, 05:35

С приятелите ми се напихме с коняк, всички се прибраха, а аз глупаво извиках такси (беше 3 сутринта) и отидох да видя бившия си приятел, с когото се разделихме преди 4 месеца (останахме приятели). не помня как влязох във входа, стигнах до апартамента му, започнах да му разбивам вратата и да викам "ЖЕНИ СЕ ЗА МЕН МАРАТ", той, горкият, полудя. Завлече ме вкъщи и под студен душ, даде ми силен чай .. След два часа си тръгнах и тогава, когато разбрах какво съм направила, НАИСТИНА МЕ Е СРАМ.След това се помирихме и още сме заедно. След това не пия повече чаша шампанско.

Това е доста истинска историялюбов.
И за ползите от пиенето също.

(Пийте, момичета, и щастието ще дойде при вас.)

В мрежата има доста решения за емулиране на многопоточност в PHP. Най-често те са базирани на разклонения, но има и вариации на темата с помощта на curl, proc_open и т.н.

По една или друга причина всички варианти, които срещнах, не ме устройваха и трябваше да напиша собствено решение.
Имах следния набор от изисквания:

  • Използване на вилици;
  • Синхронен режим със запазване на интерфейса при липса на необходимите разширения;
  • Повторно използване на дъщерни процеси;
  • Пълен обмен на данни между процесите. Тези. стартирайте с аргументи и получете резултата, когато приключите;
  • Възможност за обмен на събития между дъщерен процес „нишка“ и основния процес по време на работа;
  • Работа с пул от нишки, като същевременно се поддържа повторно използване, предаване на аргументи и получаване на резултати;
  • Обработка на грешки по време на изпълнение;
  • Изчакване за изпълнение на работа, изчакване на работа от нишка, инициализация;
  • Максимална производителност;
Резултатът е библиотека AzaThread(старо име - CThread).

За нетърпеливите, ето линк към източника:
github.com/Anizoptera/AzaThread

Описание

AzaThread предоставя прост интерфейс за създаване на класове нишки. Които всъщност използват отделни процеси, за да работят асинхронно, но не трябва да ви пука за това. Можете да изпращате събития от нишка, да връщате резултати, да използвате една нишка много пъти, като й предавате аргументи за стартиране, или да създадете група от 16 нишки, които изравняват задачите ви като топъл хляб, без да обръщате внимание на факта, че работата се случва в различни процеси .

Освен това можете лесно да тествате производителността на библиотеката в различни режими, като изберете оптималния брой нишки и опцията за прехвърляне на данни между процеси специално за вашата конфигурация.

Следните разширения са необходими за пълна работа: libevent, позиксИ pcntl.

Библиотеката използва LibEvent и сдвоени сокети за комуникация между процесите. Поддържа 5 опции за предаване на данни (аргументи, резултати и данни за събития)!

Представям опциите веднага с данни за ефективността. Тестван с група от осем нишки на Intel Core i7 2600K 3,40 Ghz (Ubuntu 11.04 на виртуална машина VMware). Дадени са средните резултати за 10 повторения на теста в jps (работи в секунда - броят задачи, които просто получават аргументи и изпращат данни в секунда).

Автоматично се избира разширението за работа със сокети. Използва се разширението, ако е налично гнезда, което дава подобрена производителност. В противен случай ще се използва поток.

Детският процес слуша всички налични сигнали. По подразбиране всички (с изключение на SIGWINCH и SIGINFO) са последвани от изключване. Но това може лесно да бъде отменено чрез създаване на метод в класа на нишката с името на сигнала. Например sigWinch.

В родителския процес всички сигнали също се прихващат по подразбиране. Това може да се промени чрез задаване на параметъра клас слушай MasterSignalsдо невярно. В този случай ще се обработва само SIGCHLD. Можете лесно да добавите свои собствени манипулатори, като създадете статичен метод, наречен м< имя сигнала > . Например mSigTerm.

Ако дъщерен процес умре по някаква причина, класът автоматично ще се разклони, когато се стартира нова задача. Това се случва незабелязано и изобщо не е нужно да мислите за това. Екземплярът просто не е необходимо да се създава отново в случай на грешка.

Дъщерният процес периодично проверява съществуването на родителския процес. Ако внезапно умре, детето автоматично ще приключи.

Всички ресурси, използвани от нишка или пул от нишки, се почистват автоматично при извикване на деструктора. Но те могат да бъдат изчистени принудително чрез извикване на метода почисти. В този случай нишката/пулът вече не може да се използва.

При стандартни настройкинишката се инициализира предварително, веднага след създаването на класа. Ако зададете параметъра префоркна false, тогава разклонението ще се случи само в момента на стартиране на задачата.

Като цяло има доста много персонализирани параметри. Промяна на името на дъщерния процес след разклонение (параметър pNameконструктор), изчакване за продължителността на задачата ( timeoutWork), таймаут за максималното време, което дъщерен процес може да чака за задачи ( изчакване MaxWait), изчакване за времето преди инициализация ( timeoutInit), размери на буфера за четене на сокет ( pipeReadSize, pipeMasterReadSize).
Можете да деактивирате режима на многозадачност за нишки ( многозадачност). В този случай всеки път, когато задачата бъде изпълнена, дъщерният процес ще умре и ще се разклони отново за следващото стартиране. Това значително ще намали производителността.

Кодът е покрит с тестове и е документиран подробно; примери за използване могат да се видят и стартират във файла пример.php.
| Повече ▼ сложни примерис обработка на грешки може да се види в кода за тест на единица.

Има режим за отстраняване на грешки, в който много подробна информацияза това какво точно се случва и къде.

Примери за използване

Основната характеристика е максималната простота. Ако просто искате да стартирате нещо в отделна „нишка“, следният код е достатъчен:
class ExampleThread extends Thread ( protected function process() ( // Някои работи тук ) ) $thread = new ExampleThread(); $thread->wait()->run();
Ако има всичко необходимо за пълноценна работа, тогава задачата ще бъде изпълнена асинхронно. Ако не, тогава всичко ще продължи да работи, но в синхронен режим.

Чрез предаване на параметър и получаване на резултата кодът ще изглежда малко по-сложен:
клас ExampleThread разширява Thread ( защитена функция process() ( return $this->getParam(0); ) ) $thread = new ExampleThread(); $thread->wait()->run(123); $result = $thread->wait()->getResult();

По същия начин, с леко махване на ръката, добавяме обработка на събития от потока:
class ExampleThread разширява Thread ( const EV_PROCESS = "процес"; защитена функция process() ( $events = $this->getParam(0); for ($i = 0; $i< $events; $i++) { $event_data = $i; $this->trigger(self::EV_PROCESS, $event_data); ) ) ) // Допълнителен аргумент. $допълнителенаргумент = 123; $thread->bind(ExampleThread::EV_PROCESS, function($event_name, $event_data, $additional_arg) ( // обработка на събитие), $additionalArgument); $събития = 10; // брой събития, които нишката ще генерира // За да избегнете ръчно изчакване на нишката преди първото извикване, // можете да замените свойството preforkWait на TRUE в наследствения клас $thread->wait(); $нишка = нова Примерна нишка(); $thread->run($events)->wait();

И накрая, използване на набор от осем нишки с обработка на грешки по време на изпълнение:
$threads = 8 // Брой нишки $pool = new ThreadPool("Примерна нишка", $threads); $num = 25; // Брой задачи $left = $num; // Брой оставащи задачи do ( // Ако има свободни нишки в пула // И все още имаме задачи за изпълнение, докато ($pool->hasWaiting() && $left > 0) ( // При стартиране получаваме идентификаторът на нишката $threadId = $pool->run(); $left--; ) if ($results = $pool->wait($failed)) ( foreach ($results as $threadId => $result) ( / / Успешно завършена задача // Резултатът може да бъде идентифициран // чрез идентификатора на нишката ($threadId) $num--; ) ) if ($failed) ( // Обработване на грешки при изпълнение. // Заданието се счита за неуспешно завършено // ако дъщерният процес е умрял по време на изпълнение или // е изтекъл таймаут за изпълнение на задача foreach ($failed as $threadId) ( $left++; ) ) ) while ($num > 0); // Прекратете всички дъщерни процеси. Ние почистваме ресурсите, използвани от пула. $pool->cleanup();

Резултати от теста за ефективност

Проведох тестовете на две машини с Ubuntu 11.04.
Първият е Intel Core i3 540 3.07 Ghz
Вторият е Intel Core i7 2600K 3,40 Ghz (Ubuntu работи на виртуална машина VMware)

Представям резултатите просто, за да можете да оцените увеличението на производителността.
Отново, това са средните резултати за поредица от 10 повторения на теста в jps (работи в секунда - брой задачи в секунда).

Като задача нишките изпълняват следния боклук:
за ($i = 0; $i< 1000; $i++) { $r = mt_rand(0, PHP_INT_MAX) * mt_rand(0, PHP_INT_MAX); }
Първият резултат е показан за режим на синхронна работа (без вилки).
Не опитах 18 и 20 нишки на първата конфигурация, тъй като вече за 12 производителността започна да пада.

Брой нишки Първа конфигурация Второ
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

Тоест, производителността се увеличава с 2-4 пъти или повече, в зависимост от процесора!

Кодът, който изпълнява серия от тестове с необходимите параметри, е във файла examples/speed_test.php. Така че можете лесно да тествате производителността и да изберете оптималния брой нишки за себе си.

В мрежата има доста решения за емулиране на многопоточност в PHP. Най-често те са базирани на вилици, но има и вариации на използването на темата къдрица, proc_openи така нататък.

Всички варианти, на които се натъкнах, не ме устройваха по една или друга причина и трябваше да напиша собствено решение. Имах следния набор от изисквания:

  • Използване на вилици;
  • Синхронен режим със запазване на интерфейса при липса на необходимите разширения;
  • Повторно използване на дъщерни процеси;
  • Пълен обмен на данни между процесите. Тези. стартирайте с аргументи и получете резултата, когато приключите;
  • Възможност за обмен на събития между дъщерен процес „нишка“ и основния процес по време на работа;
  • Работа с пул от нишки, като същевременно се поддържа повторно използване, предаване на аргументи и получаване на резултати;
  • Обработка на грешки по време на изпълнение;
  • Изчакване за изпълнение на работа, изчакване на работа от нишка, инициализация;
  • Максимална производителност.

Резултатът беше библиотеката AzaThread (по-рано CThread).

Описание

AzaThread предоставя прост интерфейс за създаване на класове нишки. Които всъщност използват отделни процеси, за да работят асинхронно, но не трябва да ви пука за това. Можете да изпращате събития от нишка, да връщате резултати, да използвате една нишка няколко пъти, като ѝ предавате начални аргументи или да създадете набор от 16 нишки, които грабват вашите задачи като топъл хляб, без да обръщате внимание на факта, че работата се случва в различни процеси.

Освен това можете лесно да тествате производителността на библиотеката в различни режими, като изберете оптималния брой нишки и опцията за прехвърляне на данни между процеси специално за вашата конфигурация.

Следните разширения са необходими за пълна работа: libevent, позиксИ pcntl.

Библиотеката използва LibEvent и сдвоени сокети за комуникация между процесите. Поддържа 5 опции за предаване на данни (аргументи, резултати и данни за събития)!

Представям опциите веднага с данни за ефективността. Тестван с група от осем нишки на Intel Core i7 2600K 3,40 Ghz (Ubuntu 11.04 на виртуална машина VMware). Дадени са средните резултати за 10 повторения на теста в jps (работи в секунда - броят задачи, които просто получават аргументи и изпращат данни в секунда).

Автоматично се избира разширението за работа със сокети. Използва се разширението, ако е налично гнезда, което дава подобрена производителност. В противен случай ще се използва поток.

Детският процес слуша всички налични сигнали. По подразбиране всички (с изключение на SIGWINCH и SIGINFO) са последвани от изключване. Но това може лесно да бъде отменено чрез създаване на метод в класа на нишката с името на сигнала. Например sigWinch.

В родителския процес всички сигнали също се прихващат по подразбиране. Това може да се промени чрез задаване на параметъра на класа listenMasterSignals на false. В този случай ще се обработва само SIGCHLD. Можете лесно да добавите свои собствени манипулатори, като създадете статичен метод, наречен m<имя сигнала>. Например mSigTerm.

Ако дъщерен процес умре по някаква причина, класът автоматично ще се разклони, когато се стартира нова задача. Това се случва незабелязано и изобщо не е нужно да мислите за това. Екземплярът просто не е необходимо да се създава отново в случай на грешка.

Дъщерният процес периодично проверява съществуването на родителския процес. Ако внезапно умре, детето автоматично ще приключи.

Всички ресурси, използвани от нишка или пул от нишки, се почистват автоматично при извикване на деструктора. Но те могат да бъдат почистени принудително чрез извикване на метода за почистване. В този случай нишката/пулът вече не може да се използва.

При стандартни настройки нишката се инициализира предварително, веднага след създаването на класа. Ако зададете параметъра prefork на false, тогава разклонението ще се случи само в момента на стартиране на задачата.

Като цяло има доста много персонализирани параметри. Промяна на името на дъщерния процес след разклонението (параметър pName на конструктора), таймаут за продължителността на изпълнение на задачата (timeoutWork), таймаут за максималното време, в което дъщерният процес чака за задачи (timeoutMaxWait), таймаут за пре- време за инициализация (timeoutInit), размер на буферите за четене на сокети (pipeReadSize, pipeMasterReadSize). Можете да деактивирате режима на многозадачност за нишки (многозадачност). В този случай всеки път, когато задачата бъде изпълнена, дъщерният процес ще умре и ще се разклони отново за следващото стартиране. Това значително ще намали производителността.

Кодът е покрит с тестове и е документиран подробно; примери за използване могат да се видят и стартират във файла example.php. По-сложни примери с обработка на грешки могат да се видят в кода за единичен тест.

Има режим за отстраняване на грешки, който показва много подробна информация какво точно се случва и къде.

Примери за използване

Основната характеристика е максималната простота. Ако просто искате да стартирате нещо в отделна "нишка", следният код е достатъчен:

Клас ExampleThread разширява Thread ( защитена функция process() ( // Някои работи тук ) ) $thread = new ExampleThread(); $thread->wait()->run();

Ако има всичко необходимо за пълноценна работа, тогава задачата ще бъде изпълнена асинхронно. Ако не, тогава всичко ще продължи да работи, но в синхронен режим.

Чрез предаване на параметър и получаване на резултат, кодът ще изглежда малко по-сложен:

Клас ExampleThread разширява Thread ( защитена функция process() ( return $this->getParam(0); ) ) $thread = new ExampleThread(); $thread->wait()->run(123); $result = $thread->wait()->getResult();

По същия начин, с леко махване на ръката, добавяме обработка на събития от потока:

Клас ExampleThread разширява Thread ( const EV_PROCESS = "процес"; защитена функция process() ( $events = $this->getParam(0); for ($i = 0; $i trigger(self::EV_PROCESS, $event_data); ) ) ) // Допълнителен аргумент. $допълнителенаргумент = 123; $thread->bind(ExampleThread::EV_PROCESS, function($event_name, $event_data, $additional_arg) ( // обработка на събитие), $additionalArgument); $събития = 10; // брой събития, които нишката ще генерира // За да избегнете ръчно изчакване на нишката преди първото извикване, // можете да замените свойството preforkWait на TRUE в наследствения клас $thread->wait(); $нишка = нова Примерна нишка(); $thread->run($events)->wait();

И накрая, използване на набор от осем нишки с обработка на грешки по време на изпълнение:

$threads = 8 // Брой нишки $pool = new ThreadPool("Примерна нишка", $threads); $num = 25; // Брой задачи $left = $num; // Брой оставащи задачи do ( // Ако има свободни нишки в пула // И все още имаме задачи за изпълнение, докато ($pool->hasWaiting() && $left > 0) ( // При стартиране получаваме идентификаторът на нишката $threadId = $pool->run(); $left--; ) if ($results = $pool->wait($failed)) ( foreach ($results as $threadId => $result) ( / / Успешно завършена задача // Резултатът може да бъде идентифициран // чрез идентификатора на нишката ($threadId) $num--; ) ) if ($failed) ( // Обработване на грешки при изпълнение. // Заданието се счита за неуспешно завършено // ако дъщерният процес е умрял по време на изпълнение или // е изтекъл таймаут за изпълнение на задача foreach ($failed as $threadId) ( $left++; ) ) ) while ($num > 0); // Прекратете всички дъщерни процеси. Ние почистваме ресурсите, използвани от пула. $pool->cleanup();

Резултати от теста за ефективност

Проведох тестовете на две машини с Ubuntu 11.04.
Първият е Intel Core i3 540 3.07 Ghz.
Вторият е Intel Core i7 2600K 3.40 Ghz (Ubuntu работи на виртуална машина на VMware).

Представям резултатите просто, за да можете да оцените увеличението на производителността. Отново това са средните резултати за серия от 10 повторения на теста в jps (jobs per second – брой задачи за секунда).

Като задача нишките изпълняват следния боклук:

За ($i = 0; $i

Първият резултат е показан за режим на синхронна работа (без вилки). Не опитах 18 и 20 нишки на първата конфигурация, тъй като вече за 12 производителността започна да пада.

Брой нишки Първа конфигурация Второ
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

Тоест, производителността се увеличава с 2-4 пъти или повече, в зависимост от процесора!

Кодът, който изпълнява серия от тестове с необходимите параметри, е във файла examples/speed_test.php. Така че можете лесно да тествате производителността и да изберете оптималния брой нишки за себе си.

Много ще се радвам, ако библиотеката е полезна на някого. Всички заявки за функции или открити грешки могат да бъдат оставени в Github, аз незабавно ще коригирам и подобря библиотеката.

Изглежда, че PHP разработчиците рядко използват паралелност. Няма да говоря за простотата на синхронния код; еднопоточното програмиране, разбира се, е по-просто и по-ясно, но понякога малко използване на паралелизъм може да доведе до забележимо увеличение на производителността.

В тази статия ще разгледаме как може да се постигне многопоточност в PHP с помощта на разширението pthreads. Това ще изисква инсталирана ZTS (Zend Thread Safety) версия на PHP 7.x, заедно с инсталираното разширение pthreads v3. (По време на писането, в PHP 7.1, потребителите ще трябва да инсталират от главния клон в хранилището на pthreads - вижте разширението на трета страна.)

Малко уточнение: pthreads v2 е предназначен за PHP 5.x и вече не се поддържа, pthreads v3 е за PHP 7.x и се разработва активно.

След такова отклонение, да минем направо на въпроса!

Обработка на еднократни задачи

Понякога искате да обработвате еднократни задачи по многонишков начин (например изпълнение на някаква I/O-обвързана задача). В такива случаи можете да използвате класа Thread, за да създадете нова нишка и да изпълните обработка на отделна нишка.

Например:

$task = new class extends Thread ( private $response; public function run() ( $content = file_get_contents("http://google.com"); preg_match("~ (.+)~", $content, $matches); $this->response = $matches; ) ); $task->start() && $task->join(); var_dump($task->response); // низ (6) "Google"

Тук методът за изпълнение е нашата обработка, която ще бъде изпълнена в нова нишка. Когато се извика Thread::start, се създава нова нишка и се извиква методът run. След това присъединяваме дъщерната нишка обратно към основната нишка, като извикаме Thread::join, което ще блокира, докато дъщерната нишка завърши изпълнението. Това гарантира, че задачата ще приключи с изпълнението си, преди да се опитаме да отпечатаме резултата (който се съхранява в $task->response).

Може да не е желателно да замърсявате клас с допълнителни отговорности, свързани с логиката на потока (включително отговорността за дефиниране на метод за изпълнение). Можем да различим такива класове, като ги наследим от класа Threaded. След това те могат да бъдат стартирани в друга нишка:

Class Task разширява Threaded ( public $response; public function someWork() ( $content = file_get_contents("http://google.com"); preg_match("~ (.+) ~", $content, $matches); $ this->response = $matchs; ) ) $task = нова задача; $thread = new class($task) extends Thread ( private $task; public function __construct(Threaded $task) ( $this->task = $task; ) public function run() ( $this->task->someWork( ); ) ); $thread->start() && $thread->join(); var_dump($task->response);

Всеки клас, който трябва да се изпълнява в отделна нишка трябва данаследяват от класа Threaded. Това е така, защото предоставя необходимите възможности за извършване на обработка на различни нишки, както и имплицитна сигурност и полезни интерфейси (като синхронизация на ресурси).

Нека да разгледаме йерархията на класовете, предлагана от разширението pthreads:

Threaded (имплементира Traversable, Collectable) Thread Worker Volatile Pool

Вече разгледахме и научихме основите на класовете Thread и Threaded, сега нека да разгледаме другите три (Worker, Volatile и Pool).

Повторно използване на нишки

Стартирането на нова нишка за всяка задача, която трябва да бъде паралелизирана, е доста скъпо. Това е така, защото трябва да се имплементира архитектура с нищо общо в pthreads, за да се постигне многонишковост в PHP. Което означава, че целият контекст на изпълнение на текущия екземпляр на PHP интерпретатора (включително всеки клас, интерфейс, характеристика и функция) трябва да бъде копиран за всяка създадена нишка. Тъй като това има забележимо въздействие върху производителността, потокът винаги трябва да се използва повторно, когато е възможно. Нишките могат да се използват повторно по два начина: с помощта на Workers или с помощта на Pools.

Класът Worker се използва за синхронно изпълнение на редица задачи в друга нишка. Това се прави чрез създаване на нов Worker екземпляр (който създава нова нишка) и след това избутване на задачи в стека на тази отделна нишка (използвайки Worker::stack).

Ето един малък пример:

Class Task extends Threaded ( private $value; public function __construct(int $i) ( $this->value = $i; ) public function run() ( usleep(250000); echo "Task: ($this->value) \n"; ) ) $работник = нов работник(); $worker->start(); for ($i = 0; $i стек(нова задача($i)); ) докато ($worker->collect()); $worker->shutdown();

В примера по-горе 15 задачи за нов $worker обект се изпращат в стека чрез метода Worker::stack и след това се обработват в реда, в който са изпратени. Методът Worker::collect, както е показано по-горе, се използва за почистване на задачи веднага щом завършат изпълнението им. С него, в рамките на цикъла while, блокираме основната нишка, докато всички задачи в стека не бъдат завършени и изчистени - преди да извикаме Worker::shutdown. Прекратяването на работник по-рано (т.е. докато все още има задачи, които трябва да бъдат изпълнени) все още ще блокира основната нишка, докато всички задачи не завършат изпълнението си, само че задачите няма да бъдат събрани за боклук (което води до изтичане на памет).

Класът Worker предоставя няколко други метода, свързани с неговия стек от задачи, включително Worker::unstack за премахване на последната подредена задача и Worker::getStacked за получаване на броя на задачите в стека за изпълнение. Стекът на работника съдържа само задачите, които трябва да бъдат изпълнени. След като дадена задача в стека бъде изпълнена, тя се премахва и се поставя на отделен (вътрешен) стек за събиране на боклук (с помощта на метода Worker::collect).

Друг начин за повторно използване на нишка в множество задачи е използването на пул от нишки (чрез класа Pool). Пулът от нишки използва група от работници, за да позволи изпълнението на задачи едновременно, в който коефициентът на едновременност (броят нишки на пула, с които работи) се задава при създаването на пула.

Нека адаптираме горния пример, за да използваме набор от работници:

Class Task extends Threaded ( private $value; public function __construct(int $i) ( $this->value = $i; ) public function run() ( usleep(250000); echo "Task: ($this->value) \n"; ) ) $пул = нов басейн(4); for ($i = 0; $i submit(new Task($i)); ) while ($pool->collect()); $pool->shutdown();

Има няколко забележителни разлики при използване на пул за разлика от работник. Първо, пулът не трябва да се стартира ръчно; той започва да изпълнява задачи веднага щом станат достъпни. Второ, ние изпратизадачи към басейна, не поставете ги на стек. Освен това класът Pool не наследява от Threaded и следователно не може да бъде предаден на други нишки (за разлика от Worker).

как добра практикаЗа работниците и пуловете винаги трябва да почиствате техните задачи веднага щом завършат, и след това ръчно да ги прекратите сами. Нишките, създадени с помощта на клас Thread, също трябва да бъдат прикачени към родителската нишка.

pthreads и (не)променливост

Последният клас, който ще разгледаме, е Volatile, ново допълнение към pthreads v3. Неизменността се превърна във важна концепция в pthreads, защото без нея производителността страда значително. Следователно по подразбиране свойствата на Threaded класове, които сами по себе си са Threaded обекти, вече са неизменни и следователно не могат да бъдат презаписани след първоначалното им присвояване. Понастоящем се предпочита изричната променливост за такива свойства и все още може да се постигне с помощта на новия клас Volatile.

Нека да разгледаме пример, който ще демонстрира новите ограничения за неизменност:

Class Task разширява Threaded // a Threaded клас ( публична функция __construct() ( $this->data = new Threaded(); // $this->data не може да се презаписва, тъй като е свойство Threaded на Threaded клас) ) $task = new class(new Task()) extends Thread ( // клас Threaded, тъй като Thread разширява публичната функция Threaded __construct($tm) ( $this->threadedMember = $tm; var_dump($this->threadedMember-> данни); // object(Threaded)#3 (0) () $this->threadedMember = new StdClass(); // невалиден, тъй като свойството е Threaded член на Threaded клас ));

Нишковидните свойства на класовете Volatile, от друга страна, са променливи:

Class Task extends Volatile ( public function __construct() ( $this->data = new Threaded(); $this->data = new StdClass(); // валиден, тъй като сме в непостоянен клас)) $task = new class(new Task()) extends Thread ( public function __construct($vm) ( $this->volatileMember = $vm; var_dump($this->volatileMember->data); // object(stdClass)#4 (0) () // все още е невалиден, тъй като Volatile разширява Threaded, така че свойството все още е Threaded член на Threaded клас $this->volatileMember = new StdClass(); ));

Можем да видим, че класът Volatile отменя неизменността, наложена от родителския клас Threaded, за да предостави възможност за промяна на свойствата на Threaded (както и unset()).

Има още един предмет на дискусия, който обхваща темата за променливостта и класа Volatile - масивите. В pthreads масивите автоматично се прехвърлят към обекти Volatile, когато са присвоени на свойство на класа Threaded. Това е така, защото просто не е безопасно да се манипулира масив от множество PHP контексти.

Нека отново да разгледаме един пример, за да разберем някои неща по-добре:

$масив = ; $task = new class($array) extends Thread ( private $data; public function __construct(array $array) ( $this->data = $array; ) public function run() ( $this->data = 4; $ това->данни = 5; print_r($този->данни); )); $task->start() && $task->join(); /* Изход: Променлив обект ( => 1 => 2 => 3 => 4 => 5) */

Виждаме, че Volatile обектите могат да се третират като масиви, защото поддържат операции с масиви като (както е показано по-горе) операторът subset(). Класовете Volatile обаче не поддържат основни функции на масиви като array_pop и array_shift. Вместо това класът Threaded ни предоставя такива операции като вградени методи.

Като демонстрация:

$data = нов клас разширява Volatile ( public $a = 1; public $b = 2; public $c = 3; ); var_dump($данни); var_dump($data->pop()); var_dump($data->shift()); var_dump($данни); /* Изход: 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) ) */

Други поддържани операции включват Threaded::chunk и Threaded::merge.

Синхронизация

В последния раздел на тази статия ще разгледаме синхронизацията в pthreads. Синхронизацията е метод, който ви позволява да контролирате достъпа до споделени ресурси.

Например, нека внедрим прост брояч:

$counter = нов клас разширява Thread ( public $i = 0; public function run() ( for ($i = 0; $i i; ) ) ); $counter->start(); за ($i = 0; $i i; ) $counter->join(); var_dump($counter->i); // ще отпечата число от 10 до 20

Без използването на синхронизация изходът не е детерминиран. Множество нишки записват в една и съща променлива без контролиран достъп, което означава, че актуализациите ще бъдат загубени.

Нека поправим това, така че да получим правилния изход от 20 чрез добавяне на времето:

$counter = new class extends Thread ( public $i = 0; public function run() ( $this->synchronized(function () ( for ($i = 0; $i i; ) )); ) ); $counter->start(); $counter->synchronized(function ($counter) ( for ($i = 0; $i i; ) ), $counter); $counter->join(); var_dump($counter->i); // int(20)

Синхронизираните кодови блокове могат също да комуникират помежду си с помощта на методите Threaded::wait и Threaded::notify (или Threaded::notifyAll).

Ето алтернативно увеличение в два синхронизирани цикъла while:

$counter = new class extends Thread ( public $cond = 1; public function 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(); // изчакайте задруго за стартиране първо) за ($i = 10; $i notify(); if ($counter->cond === 2) ( $counter->cond = 1; $counter->wait(); ) ) ) , $брояч); $counter->join(); /* Изход: 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) */

Може да забележите допълнителни условия, които бяха поставени около извикването на Threaded::wait . Тези условия са критични, защото позволяват синхронизираното обратно извикване да се възобнови, когато е получило известие и определеното условие е вярно. Това е важно, защото известията могат да идват от места, различни от това, когато се извиква Threaded::notify. По този начин, ако извикванията към метода Threaded::wait не са затворени в условия, ние ще изпълним фалшиви обаждания за събуждане, което ще доведе до непредвидимо поведение на кода.

Заключение

Разгледахме петте класа на пакета pthreads (Threaded, Thread, Worker, Volatile и Pool) и как се използва всеки клас. Разгледахме и новата концепция за неизменност в pthreads кратък прегледподдържани възможности за синхронизация. С тези основи вече можем да започнем да разглеждаме как pthreads могат да се използват в реални случаи! Това ще бъде темата на следващата ни публикация.

Ако се интересувате от превода на следващата публикация, уведомете ме: коментирайте в социалните медии. мрежи, гласувайте и споделете публикацията с колеги и приятели.

Зареждане...Зареждане...