Безпомощна дискусионна нишка php. Многонишково програмиране в PHP с превод на Pthreads

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



Обмислям такава задача. Има набор от задачи, които трябва да бъдат изпълнени бързо. PHP има други инструменти за решаване на този проблем, те не са споменати тук, статията е за pthreads.



Какво представляват pthreads

Това е всичко! Е, почти всичко. Всъщност има нещо, което може да разстрои любознателния читател. Нищо от това не работи на стандартен PHP, компилиран с опции по подразбиране. За да се насладите на многопоточност, трябва да имате активиран ZTS (Zend Thread Safety) във вашия PHP.

Настройка на PHP

След това PHP със ZTS. Не обръщайте внимание на голямата разлика във времето за изпълнение в сравнение с PHP без ZTS (37,65 срещу 265,05 секунди), не се опитах да обобщя настройката на PHP. В случая без ZTS имам активиран XDebug например.


Както можете да видите, когато използвате 2 нишки, скоростта на изпълнение на програмата е приблизително 1,5 пъти по-висока, отколкото в случая на линеен код. При използване на 4 нишки - 3 пъти.


Можете да отбележите, че въпреки че процесорът е 8-ядрен, времето за изпълнение на програмата остава почти непроменено, ако се използват повече от 4 нишки. Изглежда, че това се дължи на факта, че моят процесор има физически ядра 4. За по-голяма яснота изобразих табелата под формата на диаграма.


Резюме

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

Тагове: Добавете тагове

Майката на една моя добра приятелка загуби куфара си при полет от Санкт Петербург до Москва и имаше по-нататъшен полет до по-топлите брегове и вече беше в курорта - без бански, сандали и само с Т -риза от ръчния й багаж. За старо време й дадох няколко съвета какво да прави и къде да бяга, а днес реших да напиша тук всичко, което знам по дадена тема.

За да обясня откъде съм толкова умен, нека ви напомня, че по едно време работих в наземни служби за няколко авиокомпании, включително и занимавах се с някои въпроси, свързани с търсенето на багаж. Е, плюс собствения ми летателен опит, разбира се. Въпреки това, защото Напуснах индустрията за авиационни услуги преди няколко години, може би някои нюанси може да са се променили - ако е така, с благодарност ще приема коментари по темата и ще коригирам информацията в публикацията.

Ще започна с това Какво трябва да направите, за да предотвратите загуба на багажа си:
1. Откъснете от куфара си всички етикети и стикери от предишни пътувания, дори и малките с баркод, които често са залепени отделно за самия куфар – могат да объркат системата за автоматично сканиране и сортиране на багажа.
2. Закачете етикет с име на куфара си (чанта, кутия, пакет - като цяло всичко, което регистрирате като багаж): можете да закупите опция за многократна употреба предварително или да вземете хартиен етикет на гишето за чекиране - обикновено всички повече или по - малко приличните авиокомпании ги раздават без ограничения . И Emirates, например, обикновено има отлични пластмасови етикети върху издръжлив кабел, който може да издържи много дълго време:

Старите параноици могат да направят като мен: винаги имам пластмасов етикет за многократна употреба от комплекта Samsonite, окачен на куфара ми с постоянния ми домашен адрес, телефонен номер и имейл, а когато летя някъде на почивка, допълнително окачвам хартиен, на който посочете датите на престоя ми на ново място и всички възможни контакти (име и адрес на хотела, неговия местен телефонен номер, ако има такъв, и вашето име и фамилия, разбира се).
3. На гишето за чекиране се уверете, че етикетът за багаж, отпечатан от агента за чекиране, е залепен върху багажа ви - с кода на града, за който летите, и номера на полета.
4. Ако имате няколко свързващи полета, уведомете агента за чекиране за това и уточнете до коя точка искате да чекирате багажа си. В някои случаи багажът ще трябва да бъде взет на едно или друго летище по маршрута, независимо от вашето желание: това се отнася например за трансфери между летища (Орли и Шарл де Гол в Париж, Домодедово - Шереметиево - "Внуково" " в Москва), отделни терминали (терминали 1 и 2 във Франкфурт) или в първата точка на пристигане в САЩ или Мексико - това е митническо изискване в тези страни: да предположим, че летите Москва-Вашингтон-Феникс, етикет за багаж се издава и за трите сегмента до Финикс, но във Вашингтон багажът ще трябва да бъде физически взет, освободен през митницата и чекиран отново.Освен това, ако чекирате бебешка количка, която ви беше позволено да вземете, преди да се качите на борда самолет или животно, вероятно ще трябва да го вземете от транзитен пункт. Като цяло, в случай на сложен маршрут с трансфери, е по-добре да изясните подробностите за движението на багажа предварително в кол центъра на авиокомпанията или, в краен случай, при регистрация.
5. Направете багажа си видим: закъсненията на багажа не винаги са по вина на работниците, занимаващи се с багажа, или на грешки в системата за сортиране. Понякога друг разсеян пътник, уморен след дълъг полет, ще вземе от въртележката за багаж същата черна чанта Samsonite или невзрачна спортна чанта като вашата. Затова маркирайте багажа си: закачете куп ярки панделки или малка мека играчка на дръжката, залепете върху нея голям стикер или просто дайте предпочитание на необичаен цвят при избора на куфар.

Какво не трябва да се регистрира в багажа?
Не забравяйте, че всички авиокомпании и летища губят багаж. Разбира се, статистиката е различна за всеки, но дори и най-надеждните авиокомпании могат да загубят или забавят багажа, дори и на най-малкото летище, където един-единствен багажник ще транспортира количка с куфари директно от гишето за чекиране до самолета. Затова ви съветвам винаги да вземете в ръчния си багаж:
- важни документи, включително такива, които не са необходими по време на полета (например при последното ми пътуване до Санкт Петербург трябваше да сменя лиценза си и взех със себе си в ръчния багаж брачно свидетелство и всякакви карти от шофьорска школа)
- ключове (в комбинация с етикет с вашия адрес, това може да бъде опасно)
- пари, бижута (без коментари)
- скъпо чупливо оборудване
- лекарства, които редовно приемате, в необходимото за полета количество и с малък резерв, в случай че се наложи да търсите аналог в чужда държава или град. Лекарства с рецепта, които не могат да бъдат закупени, ако багажът ви бъде изгубен, вземете със себе си в необходимото количество за цялото пътуване.
- нещо, което може да ви потрябва спешно при пристигането (например зарядно за телефон
- нещо, което има сантиментална стойност лично за вас: понякога багажът се губи завинаги и ако загубата на личния ви дневник ви разбива сърцето, по-добре е да го оставите у дома или да го вземете със себе си в самолета

Една поучителна история: по време на моята работа в Lufthansa в Санкт Петербург семейна двойка от САЩ дотича в нашия офис, кършейки ръце - багажът им, който съдържаше много важни документи за процеса на осиновяване, не беше пристигнал, делото беше на следващия ден. Разбира се, авиокомпанията е виновна за загубата на багаж, но кой има полза от това? За да избегнете такава ситуация, беше достатъчно просто да поставите важни документи в ръчния си багаж.

И така, пристигнахте и не намерихте багажа си на лентата за багаж. Какво да правя?
1. Ако сте чекирали в багажа си нещо различно от обикновени куфари: ски, виолончело, стенен плазмен панел, бебешка количка, жив мраморен дог, проверете дали има отделен пункт за издаване на т.нар. извънгабаритен багаж или обемист багаж - багаж, подобен на този, който описах по-горе, често се товари в отделно отделение и се разтоварва отделно, ръчно. Ако багажът ви не бъде открит и там
2. Отидете до гишето за проследяване на багаж или за изгубени и намерени. Там ще трябва да попълните специален формуляр с подробна информация за вашия багаж: маршрут, външен вид, кратък списък на съдържанието, вашите контакти на постоянно местоживеене и временен престой. Освен това в услугата за проследяване на багаж е по-вероятно да видите таблица на багажа като тази:

Според тази класификация вашият липсващ багаж ще бъде кодиран и, както разбирате, тези два куфара ще бъдат кодирани еднакво:

Така че не се колебайте да добавите допълнителни подробности в описанието и не пропускайте клаузата за съдържание. Като правило, когато за първи път попълвате доклад за забавяне на багаж, ще бъдете помолени да посочите няколко елемента от съдържанието, по които вашата чанта може да бъде идентифицирана, ако няма идентификационни знаци отвън и чантата трябва да бъде отворена (ако чантата е отворена, ще поставите известие за това). Лош пример: тениска / книга / мокри кърпички, добър пример: яркочервени бикини / каталог с репродукции на Малевич / сгъваема ютия. След като попълните заявлението, служителят на службата за проследяване на багажа ще ви даде номер във формат XXXYY11111, където XXX е кодът на летището за пристигане, YY е кодът на авиокомпанията за пристигане + 5 цифри от серийния номер на заявлението: например JFKLH12345, ако летяхте с Lufthansa до летище Кенеди в Ню Йорк. Запомнете или запишете този номер - това ще бъде най-лесният начин да намерите приложението си в бъдещи приложения.
Със същия номер можете САМИ да проверите състоянието на търсенето (по някаква причина връзката изчезва: ако не работи за вас, google World Tracer Online и буквално втората връзка - със заглавие Baggage Tracing на уебсайта worldtracer.aero - е това, което ви трябва), защото достигането до lost&found често е много трудно
3. Опитайте да се свържете с офиса на вашата авиокомпания на летището на пристигане: понякога (подчертавам - ПОНЯКОГА!), ако не сте летели у дома, а до място за временен престой (ваканция, командировка), авиокомпанията може да предостави комплект тоалетни принадлежности (Lufthansa ги има).включени голяма тениска, четка и паста за зъби, гребен, малки опаковки шампоан и душ гел, пакет прах за пране и др.) или направете малко плащане в брой за дребни разходи на място (плащане в брой на място).

Какво ще се случи след това?
Вашият файл (т.нар. AHL) ще отиде в централизираната система за търсене на багаж (World Tracer). Всички непотърсени багажи попадат в една и съща система за търсене, независимо дали са намерени без етикет в кътчетата на багажния двор или са останали на лентата за багаж; за всеки от тези артикули се създава файл във формат XXXYY11111 също създаден, само че от различен подтип – т.нар. отчет на ръка или OHD. Ако данните от файловете AHL и OHD съвпадат (фамилия, описание на куфара, маршрут и т.н.), и двете станции (където е докладвана загубата на багаж и където е открит непотърсеният багаж) ще получат известие и след това това е въпрос на технология: повторна проверка и при успех препращане на багажа до желания град. Разбира се, има и много ръчна работа - размяна на съобщения, отказ на подобни, но не еднакви куфари, плюс отговаряне на многократни телефонни обаждания - като цяло персоналът на службата за проследяване на багаж никога не скучае.
Приблизителна статистика: повече от 90% от изгубения багаж се намира през първите 3 дни от търсенето, 3% се губят завинаги.
Какво можеш да направиш?
1. Ако трябва да купите нещо спешно необходимо при пристигането (от четка за зъби до бизнес костюм), не забравяйте да запазите касовите си бележки за по-късна компенсация. Трябва обаче да избягвате ненужни скъпи покупки; ще обясня защо по-късно.
2. Следвайки нови стъпки, направете най-подробния списък на съдържанието, за предпочитане с цвета, марката и приблизителната цена на всеки артикул, в идеалния случай на английски (в противен случай служител на авиокомпанията ще трябва да преведе този списък за въвеждане в системата), свържете се с авиокомпания и изпрати Те получават този списък и той ще бъде добавен към приложението за търсене на багаж. През първите 5 дни търсенето на багаж се извършва от летището на пристигане, след това търсенето става отговорност на авиокомпанията превозвач (авиокомпанията, която е посочена в номера на заявлението - помните ли JFKLH12345?), а след 21 дни вие може да кандидатства за окончателно обезщетение.
3. Ако след 21 дни от датата на подаване на декларация за изгубен багаж, той не е намерен, свържете се с авиокомпанията превозвач, за да поискате обезщетение. Ако не се лъжа, давността е 2 години, т.е. Можете да кандидатствате за обезщетение в рамките на две години от датата на подаване на иск за загуба.

Изплащане на обезщетение.
За да платите обезщетение, ще трябва да се свържете с представителството на вашата авиокомпания със заявление за плащане, документи, потвърждаващи полета и факта на загуба на багаж (бордни карти, етикети за багаж, номер на иск за загуба на багаж, данни за плащане). Ако не греша, в Руската федерация решението за обезщетение трябва да бъде законово разгледано в рамките на 30 дни. Може също така да бъдете помолени да оцените цената на съдържанието и, ако е възможно, да предоставите касови бележки за покупката на куфара и вещите в него (разбирам, че в повечето случаи това е нереалистично, но това е част от процедурата).
Преди плащанията се извършваха според теглото на регистрирания багаж - около 20 долара на килограм. По-късно системата за плащане беше променена и отговорността на авиокомпаниите беше ограничена до 1000 конвенционални единици (цената на една конвенционална единица се изчислява в рамките на авиокомпанията), което по време на моята работа съответстваше на приблизително 1300 евро. Тези. дори и да донесете разписка за покупката на куфар Louis Vuitton, направен от хиляда боливийски кожи на гекони и пълнен с диаманти, няма да получите повече от 1300 евро.

Изглежда, че 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(); // изчакайте другият да започне първи) for ($i = 10; $i notify(); if ($counter->cond === 2) ( $counter->cond = 1; $counter->wait(); ) ) ), $counter); $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 могат да се използват в реални случаи! Това ще бъде темата на следващата ни публикация.

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

Дискусия в нишка

А дискусия с резбае електронна дискусия (като такава чрез електронна поща, списък с имейли, табло за обяви, дискусионна група или интернет форум), в която софтуерът помага на потребителя чрез визуално групиране на съобщения. Съобщенията обикновено са групирани визуално в йерархия по теми. Набор от съобщения, групирани по този начин, се нарича a тематична нишкаили просто "нишка". Казва се, че дискусионен форум, клиент за електронна поща или клиент за новини има „теми с нишки“, ако групира съобщения по една и съща тема заедно за лесно четене по този начин. Освен това дискусиите с нишки обикновено позволяват на потребителите да отговарят на конкретна публикация в нишката на дадена тема. В резултат на това може да има йерархия от дискусии в темата на нишката. Различни типове софтуер могат да позволят тази йерархия да се показва в това, което наречен Threaded Mode. (Алтернативата е линеен режим, който обикновено показва всички публикации по дата, независимо кой на кого конкретно е отговорил.)

Предимства

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

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

Недостатъци

Недостатък на йерархичната нишка спрямо плоската нишка е повишеното ниво на усложнение и такъв изглед следователно изисква повишено ниво на комфорт и изтънченост от страна на потребителите. Следователно не е изненадващо, че разпространението му е било най-голямо в някои от най-старите и/или най-сложните онлайн общности, като Usenet, CIX или Slashdot. Системите за уеб чат и коментари са, за сравнение, по-млади и отворени за по-широка аудитория и като такава йерархична нишка едва наскоро стана обичайна в такива арени.

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

Отворена тема

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

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

Примери

*Yahoo! Групи[ http://groups.yahoo.com/], MSN групи [ http://groups.msn.com/] и Slashdot [ http://www.slashdot.com/] всички предлагат уеб базирани форуми, които включват дискусии в нишки.

Вижте също

*Научно небесно писане
* Списък с термини за блогове

Препратки

*Дартмут. (2003). [ http://www.dartmouth.edu/~webteach/articles/discussion.html „Провеждане на дискусия онлайн“ ]
*Wolsey, T. DeVere, [ http://www.readingonline.org/articles/art_index.asp?HREF=wolsey/index.html „Литературна дискусия в киберпространството: Млади юноши използват дискусионни групи с нишки, за да говорят за книги] . "Reading Online", 7(4), януари/февруари 2004 г. Посетен на 30 декември 2007 г.

Фондация Уикимедия. 2010 г.

  • Леон Пау
  • Барх Азум

Вижте други речници:

    Интернет форум- Софтуерният пакет phpBB Internet Forum, един от най-популярните форумни пакети… Wikipedia

    История на виртуалните среди за обучение през 1990 г- В историята на виртуалните учебни среди 90-те години на миналия век бяха време на растеж, главно поради появата на достъпния компютър и на Интернет. 1990-те 1990-те* Formal Systems Inc. от Принстън, Ню Джърси, САЩ въвежда оценка, базирана на DOS… … Wikipedia

    КАФЕ- Разработчик(и) на образователна среда за сътрудничество лице в лице Консорциум LEAD Стабилна версия 5.0 / юни 2010 г. Операционна система Кръстосана платформа … Wikipedia

    Редактиране на разговори- е функция, използвана от много имейл клиенти, табла за обяви, дискусионни групи или интернет форуми, в които софтуерът помага на потребителя чрез визуално групиране на съобщения. Съобщенията обикновено са групирани визуално в йерархия по теми. Набор от групирани съобщения... ... Wikipedia

    Slashdot- Екранна снимка на URL адреса на главната страница на Slashdot.org slashdot.org Слоган Новини за маниаци. Неща, които имат значение...Уикипедия

    MediaWiki- пространството от имена пренасочва тук. За помощ относно пространството от имена на MediaWiki в Уикипедия вижте Помощ: пространство от имена на MediaWiki. За обща информация относно пространствата от имена на Wikipedia вижте Wikipedia:Пространство от имена. Страницата за разговори и страницата за разговори на MediaWiki пренасочват тук. За... ... Уикипедия

    Компютърно медиирана комуникация- За други употреби вижте CMC (многозначност). Компютърно медиираната комуникация (CMC) се определя като всяка комуникативна транзакция, която се осъществява чрез използването на два или повече компютъра в мрежа. Въпреки че терминът традиционно се отнася до тези... ... Wikipedia

    Сравнение на wiki софтуер- Следващите таблици сравняват обща и техническа информация за редица софтуерни пакети за wiki. Съдържание 1 Обща информация 2 Целева аудитория 3 Характеристики 1 4 Характеристики 2 … Wikipedia

    Научно небесно писане- е термин, измислен от когнитивния учен Стивън Харнад, описващ комбинацията от множество имейли и уеб архив с теми, като дискусионна група, електронен пощенски списък, хиперпоща, мрежови новини или интернет форум, свързани и сортирани по дата,… … Wikipedia

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

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

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

Въпреки че PHP не поддържа многопоточност, има няколко метода за емулирането му, които ще бъдат обсъдени по-долу.

1. Изпълнение на няколко копия на скрипта - по едно копие на операция

//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" ) (намери_друг_един();)

Когато изпълним този скрипт без параметри, той автоматично стартира две свои копия с идентификатори на операции ("thread=make_me_happy" и "thread=make_me_rich"), които инициират изпълнението на необходимите функции.

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

2. Пътят на джедаите - с помощта на разширението PCNTL

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

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

Изглежда доста объркващо, нека го разгледаме ред по ред.

В първия ред ние „разклоняваме“ текущия процес (разклонението копира процес, като запазва стойностите на всички променливи), разделяйки го на два процеса (текущ и дъщерен), работещи паралелно.

За да разберем дали в момента сме в дъщерен или майчин процес, функцията pcntl_fork връща 0 за дъщерния процес и идентификатора на процеса за майката. Следователно във втория ред разглеждаме $pid, ако е нула, значи сме в дъщерния процес - изпълняваме функцията, в противен случай сме в майката (ред 4), след което създаваме друг процес и изпълнете задачата по подобен начин.

Процес на изпълнение на скрипта:

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



Свързани публикации