Безпорадний discussion thread php. Багатопотокове програмування в PHP за допомогою Pthreads Переклад

Нещодавно я спробував pthreads і був приємно здивований - це розширення, яке додає в PHP можливість працювати з декількома справжніми потоками. Жодної емуляції, ніякої магії, ніяких фейків - все по-справжньому.



Я розглядаю таке завдання. Є пул завдань, які треба якнайшвидше виконати. У PHP є й інші інструменти для вирішення цього завдання, тут вони не згадуються, стаття саме про pthreads.



Що таке pthreads

От і все! Ну, майже все. Насправді є те, що може засмутити допитливого читача. Все це не працює на стандартному PHP, скомпілюваному з опціями за замовчуванням. Щоб насолодитися багатопоточністю, треба, щоб у PHP був включений ZTS (Zend Thread Safety).

Налаштування 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. Зробіть свій багаж помітним: не завжди у затримці багажу винні вантажники чи збої у системі сортування. Іноді інший розсіяний пасажир, що втомився після довгого перельоту, візьме з багажної стрічки такий самий чорний самсонайт або непоказну спортивну сумку, як і у вас. Тому відзначте свій багаж: повісьте на ручку зв'язку яскравих стрічок або невелику м'яку іграшку, наклейте на нього велику наклейку або просто на етапі вибору валізи віддайте перевагу незвичайному забарвленню.

Що не варто здавати у багаж?
Пам'ятайте, багаж втрачають усі авіакомпанії та у всіх аеропортах. Безумовно, статистика у всіх різна, але втратити або затримати багаж можуть навіть найнадійніші авіалінії і навіть у найменшому аеропорту, де один-єдиний вантажник довезе візок із валізами прямо від стійки реєстрації до літака. Тому раджу завжди брати в ручну поклажу:
- важливі документи, у тому числі ті, які не потрібні при перельоті (наприклад, в останню поїздку до Пітера мені потрібно було поміняти права, і я везла із собою в ручній поклажі свідоцтво про шлюб та всякі картки з автошколи)
- ключі (у поєднанні з биркою з вашою адресою це може бути небезпечно)
- Гроші, коштовності (без коментарів)
- дорогу тендітну техніку
- ліки, які ви регулярно приймаєте, у кількості, необхідної для перельоту, та з невеликим запасом на випадок, якщо доведеться шукати аналог у чужій країні чи місті. Ліки за рецептом, які неможливо купити в разі втрати багажу, брати з собою в обсязі, необхідному на всю поїздку.
- те, що може знадобитися терміново після приїзду (наприклад, зарядний пристрій для телефону
- те, що має сентиментальну цінність особисто для вас: іноді багаж втрачається безповоротно, і якщо втрата особистого щоденника розіб'є вам серце, краще залиште його вдома або візьміть із собою в салон літака

Повчальна історія: за часів моєї роботи в пітерській Люфтганзі, до нас в офіс, заламуючи руки, прибігла сімейна пара зі США – у них не прилетів багаж, у якому лежали дуже важливі документи для судового процесу щодо усиновлення, суд був наступного дня. Звісно, ​​у втраті багажу винна авіакомпанія, але кому від цього легше? Щоб уникнути такої ситуації, досить просто покласти важливі папери в ручну поклажу.

Отже, ви прилетіли і не знайшли свій багаж на багажній стрічці. Що робити?
1. Якщо ви здавали в багаж щось відмінне від звичайних валіз: лижі, віолончель, плазмову панель на всю стіну, дитячу коляску, живого мармурового дога, перевірте, чи немає окремого пункту видачі т.зв. негабаритного багажу або Bulky baggage - багаж, подібний до того, який я описала вище, часто завантажується в окремий відсік і так само окремо, вручну, вивантажується. Якщо і там ваш багаж не виявився
2. Ідіть на стійку пошуку багажу або Lost & Found. Там вам буде необхідно заповнити спеціальну форму з детальною інформацією про свій багаж: маршрут проходження, зовнішній вигляд, короткий список вмісту, ваші контакти на постійному місці проживання та тимчасового перебування. Також у службі розшуку багажу ви швидше побачите такий baggage chart:

Саме за цією класифікацією ваш зниклий багаж закодують і, щоб ви розуміли, ось ці дві валізи будуть закодовані однаково:

Тому не соромтеся додавати додаткові деталі в описі та не пропускайте пункт про вміст. Як правило, при первинному заповненні заяви про затримку багажу (baggage delay report) вам запропонують вказати кілька предметів вмісту, за якими вашу сумку можна буде ідентифікувати, якщо зовні на ній не знайдеться ніяких розпізнавальних знаків і сумку доведеться розкривати (якщо сумку розкриють, всередину повідомлення про це). Поганий приклад: футболка / книга / вологі серветки, гарний приклад: яскраво-червоне бікіні / каталог репродукцій Малевича / складана праска. Після заповнення заяви співробітник служби розшуку багажу видасть вам номер формату XXXYY11111, де XXX – код аеропорту прильоту, YY – код авіакомпанії прильоту + 5 цифр порядкового номера заяви: наприклад JFKLH12345, якщо ви прилетіли "Люфтганзою" до аеропорту Кеннеді в Нью-Йорку. Запам'ятайте або запишіть цей номер - за ним вашу заяву найпростіше знайти при подальших зверненнях.
За цим же номером ви можете САМІ перевіряти статус розшуку (посилання чомусь злітає: якщо у вас не працює, забіть у гугле World Tracer Online і буквально друге посилання - із заголовком Baggage Tracing на сайті worldtracer.aero - те, що вам треба), тому що додзвонитися до lost&found часто буває дуже складно
3. Спробуйте звернутися в офіс вашої авіакомпанії в аеропорту прильоту: іноді (наголошую - Іноді!) у випадку, якщо ви прилетіли не додому, а в місце тимчасового перебування (відпустка, відрядження), авіакомпанія може надати набір туалетного приладдя (у Lufthansa до нього входили безрозмірна футболка, зубна щітка та паста, гребінець, маленькі упаковки шампуню та гелю для душу, пакетик прального порошку тощо) або зробити невелику виплату готівкою на дрібні витрати на місці (spot cash payment).

Що відбуватиметься далі?
Ваш файл (т.зв. AHL) потрапить до централізованої системи пошуку багажу (World Tracer). У цю ж систему пошуку потрапляють усі незатребувані предмети багажу, байдуже, чи були знайдені без бирки в закутках багажного дворика чи залишилися на багажній стрічці, кожен із таких предметів теж заводиться файл формату XXXYY11111, лише іншого підвиду - т.зв. on-hand report або OHD. У разі збігу даних з AHL та OHD файлів (прізвище, опис валізи, маршрут та ін.), обидві станції (де заявили про втрату багажу і де був знайдений багаж незатребуваний) отримають повідомлення, ну і далі питання техніки: перевіряти ще раз і в разі удачі пересилання багажу до потрібного міста. Зрозуміло, здійснюється і велика кількість ручної роботи – обмін повідомленнями, відбраковування схожих, але не тих самих валіз, плюс відповіді на множинні телефонні дзвінки – загалом, співробітникам служби розшуку багажу нудьгувати не доводиться.
Приблизна статистика: більше 90% втраченого багажу перебувають у перші 3 дні пошуку, 3% губляться назавжди.
Що ви можете зробити?
1. Якщо вам доведеться купувати щось із екстрено необхідного після прильоту (починаючи від зубної щітки і закінчуючи діловим костюмом), обов'язково зберігайте чеки для подальшої компенсації. Втім, від дорогих покупок без потреби варто відмовитися, чому - поясню пізніше.
2. За свіжими слідами складіть максимально докладний список вмісту, бажано з кольором, брендом та зразковою вартістю кожної речі, в ідеалі англійською мовою (т.к. інакше перекладати цей список для внесення в систему доведеться співробітникові авіакомпанії), зв'яжіться з авіакомпанією та надішліть їм цей список, його додадуть до заяви про розшук багажу. Перші 5 днів розшуком багажу займається аеропорт прильоту, далі розшук переходить у ведення авіакомпанії-перевізника (та авіакомпанія, яка вказана в номері заяви – пам'ятаєте JFKLH12345?), а через 21 день можна звертатися за фінальною компенсацією.
3. Якщо після закінчення 21 дня з моменту складання заяви про втрату багажу він не був знайдений, звертайтеся до авіакомпанії-перевізника з вимогою компенсації. Якщо не помиляюся, термін давності - 2 роки, тобто. за компенсацією ви можете звернутись протягом двох років з моменту подання заяви про втрату.

Виплата компенсацій.
Для виплати компенсації вам необхідно звернутися до представництва своєї авіакомпанії із заявою на виплату, документами, що підтверджують переліт і факт втрати багажу (посадкові талони, багажні бирки, номер заяви про втрату багажу, платіжні реквізити). Якщо не помиляюся, у РФ рішення про компенсацію законодавчо має бути розглянуте протягом 30 днів. Також вас можуть попросити оцінити вартість вмісту і надати чеки на покупку валізи і речей в ній (розумію, що це малореально в більшості випадків, але це частина процедури).
Раніше виплати проводились за принципом ваги зданого багажу – близько 20 доларів за кілограм. Пізніше систему розрахунків змінили і обмежили відповідальність авіакомпаній сумою в 1000 умовних одиниць (ціна умовної одиниці розраховується всередині авіакомпанії), що на момент моєї роботи відповідало приблизно 1300 євро. Тобто. навіть якщо ви принесете чек на купівлю валізи Луї Віттон, зшитої з тисячі шкурок болівійського гекона і набитої діамантами, більше 1300 євро вам не світить.

Схоже, PHP розробники рідко використовують паралельність. Говорити про простоту синхронного коду не буду, однопоточне програмування, звичайно, простіше і зрозуміліше, але іноді невелике використання паралельності може принести відчутне підвищення продуктивності.

У цій статті ми поглянемо на те, як багатопоточність може бути досягнута в PHP за допомогою розширення pthreads. Для цього буде потрібна встановлена ​​ZTS (Zend Thread Safety) версія PHP 7.x, разом із встановленим розширенням pthreads v3. (На момент написання статті, в PHP 7.1 користувачам потрібно буде встановити з гілки master в репозиторії pthreads - див.

Невелике уточнення: pthreads v2 призначений для PHP 5.x і більше не підтримується, pthreads v3 - для PHP 7.х і активно розвивається.

Після такого відступу, давайте одразу перейдемо до справи!

Обробка разових завдань

Іноді ви хочете обробляти разові завдання багатопотоковим способом (наприклад, виконання певної задачі, зав'язаної на введення-виведення). У таких випадках можна використовувати клас 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); // string (6) "Google"

Тут метод run це наша обробка, яка буде виконуватися всередині нового потоку. При виклик Thread::start , породжується новий потік і викликається метод run . Потім ми приєднуємо породжений потік назад до основного потоку, викликавши Thread::join , який буде заблокований доти, поки породжений потік не завершить своє виконання. Це гарантує, що завдання завершить виконання, перш ніж спробуємо вивести результат (який зберігається в $task->response).

Можливо, не бажано забруднювати клас додатковою відповідальністю, що з логікою потоку (зокрема обов'язок визначення методу run). Ми можемо виділити такі класи, успадкувавши їх від класу Threaded. Тоді вони можуть бути запущені всередині іншого потоку:

Class Task extends Threaded ( public $response; public function someWork() ( $content = file_get_contents("http://google.com"); preg_match("~ (.+) ~", $content, $matches); $ this->response = $matches;)) $task = new Task; $thread = new class($task) extends Thread ( 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 (implements Traversable, Collectable) Thread Worker Volatile Pool

Ми вже розглянули і дізналися основи класів Thread і Threaded, тепер поглянемо на інші три (Worker, Volatile, і Pool).

Перевикористання потоків

Запуск нового потоку для кожного завдання, яке потрібно розпаралелити, є досить витратним. Це тому, що архітектура "нічого-загального" повинна бути реалізована в pthreads, щоб домогтися багатопоточності всередині PHP. Що означає, що весь контекст виконання поточного екземпляра інтерпретатора PHP (у тому числі й кожен клас, інтерфейс, трейт та функція) має бути скопійований для кожного створеного потоку. Оскільки це тягне помітний вплив на продуктивність, потік завжди повинен бути повторно використаний, коли це можливо. Потоки можуть бути перевикористані двома способами: за допомогою Worker-ів або за допомогою Pool-ів.

Клас 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 = new Worker(); $worker->start(); for ($i = 0; $i stack(new Task($i)); ) while ($worker->collect()); $worker->shutdown();

У наведеному прикладі в стек заноситься 15 завдань для нового об'єкта $worker через метод Worker::stack , а потім вони обробляються в порядку їх внесення. Метод Worker::collect, як показано вище, використовується для очищення завдань, як тільки вони закінчать виконання. З його допомогою всередині циклу while, ми блокуємо основний потік, доки не будуть завершені всі завдання зі стеку і поки вони не будуть очищені - до того як ми викличемо Worker::shutdown. Завершення worker -а достроково (тобто доки є ще завдання, які мають бути виконані) буде, як і раніше, блокувати основний потік доти, доки всі завдання не завершать своє виконання, просто завдання не будуть почищені збирачем сміття (що тягне за собою витоку пам'яті).

Клас Worker надає кілька інших методів, що стосуються його стеку завдань, включаючи Worker::unstack для видалення останньої внесеної задачі та Worker::getStacked для отримання кількості завдань у стеку виконання. Стек worker -а містить лише завдання, які мають бути виконані. Як тільки завдання зі стеку було виконано, воно видаляється та розміщується в окремому (внутрішньому) стеку для складання сміття (за допомогою методу Worker::collect).

Ще один спосіб перевикористовувати потік при виконанні багатьох завдань – це використання пулу потоків (через клас Pool). Пул потоків використовує групу Worker -ів, щоб дати можливість виконувати завдання одночасно, В якому фактор паралельності (кількість потоків пулу, з якими він працює) задається при створенні пулу.

Давайте адаптуємо наведений вище приклад для використання пулу worker -ів:

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

Є кілька помітних відмінностей під час використання пулу, на відміну воркера. По-перше, пул не вимагає запуску вручну, він починає виконання завдань, як тільки вони стають доступними. По-друге, ми відправляємозавдання в пул, а не вкладаємо їх у стек. Крім того, клас Pool не успадковується від Threaded і тому він не може бути переданий в інші потоки (на відміну від Worker).

Як хороша практика, для воркерів і пулів слід завжди підчищати їхні завдання, як тільки вони завершилися, а потім вручну завершувати їх самих. Потоки, створені за допомогою класу Thread, також повинні бути приєднані до потоку, що породжує.

pthreads та (не)змінність

Останній клас, якого ми торкнемося, - Volatile, - новий додаток до pthreads v3. Поняття незмінності стало важливою концепцією в pthreads, оскільки без неї продуктивність суттєво знижується. Тому за умовчанням, властивості Threaded-класів, які самі є Threaded-об'єктами, зараз є незмінними, і тому вони не можуть бути перезаписані після їхнього первісного присвоєння. Явна змінність для таких властивостей зараз поки що краща, і все ще може бути досягнута за допомогою нового класу Volatile.

Погляньмо на приклад, який продемонструє нові обмеження незмінності:

Class Task extends Threaded // a Threaded class ( public function __construct() ( $this->data = new Threaded(); // $this->data is not overwritable, since it is a Threaded property of a Threaded class ) ) $task = New class(new Task()) extends Thread ( // Threaded class, since Thread extends Threaded public function __construct($tm) ( $this->threadedMember = $tm; var_dump($this->threadedMember-> data); // object(Threaded)#3 (0) () $this->threadedMember = new StdClass();

Threaded -властивості у класів Volatile, з іншого боку, змінюються:

Class Task extends Volatile ( public function __construct() ( $this->data = new Threaded(); $this->data = new StdClass(); // valid, since we are in a volatile class ) ) $task = new class(new Task()) extends Thread ( public function __construct($vm) ( $this->volatileMember = $vm; var_dump($this->volatileMember->data); // object(stdClass)#4 (0) () // Still invalid, since Volatile extends Threaded, so the property is still a Threaded member of Threaded class $this->volatileMember = new StdClass(); ) );

Ми бачимо, що клас Volatile перевизначає незмінність, нав'язану батьківським класом Threaded , щоб надати можливість змінювати Threaded -властивості (а також unset() -ить).

Є ще один предмет обговорення, щоб розкрити тему змінності та класу Volatile - масиви. У pthreads масиви автоматично наводяться до Volatile-об'єктів при присвоєнні властивості класу Threaded . Це тому, що просто небезпечно маніпулювати масивом з кількох контекстів PHP.

Давайте знову поглянемо на приклад, щоб краще розуміти деякі речі:

$array = ; $task = New class($array) extends Thread ( private $data; public function __construct(array $array) ( $this->data = $array; ) public function run() ( $this->data = 4; $ this->data = 5;print_r($this->data); ) ); $task->start() && $task->join(); /* Висновок: Volatile Object ( => 1 => 2 => 3 => 4 => 5) */

Ми бачимо, що Volatile -об'єкти можуть бути оброблені так, ніби вони були масивами, тому що вони підтримують операції з масивами, такі як (як показано вище) оператор підмножин (). Однак, класи Volatile не підтримують базові функції з масивами, такі як array_pop та array_shift. Натомість клас Threaded надає нам подібні операції як вбудовані методи.

Як демонстрація:

$data = new class extends Volatile ( public $a = 1; public $b = 2; public $c = 3; ); var_dump($data); var_dump($data->pop()); var_dump($data->shift()); var_dump($data); /* Висновок: 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 = new class extends Thread ( public $i = 0; public function run() ( for ($i = 0; $i i; ) ) ); $counter->start(); for ($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(); // wait for the start to first ) 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(19) int(19) */

Ви можете помітити додаткові умови, які розміщені навколо звернення до Threaded::wait . Ці умови мають вирішальне значення, оскільки вони дозволяють синхронізованому колбеку відновити роботу, коли він отримав повідомлення і зазначена умова true . Це важливо, тому що повідомлення можуть надходити з інших місць, окрім Threaded::notify . Таким чином, якщо виклики методу Threaded::wait не були укладені в умовах, ми будемо виконувати помилкові виклики пробудження, які призведуть до непередбачуваної поведінки коду

Висновок

Ми розглянули п'ять класів пакету pthreads (Threaded, Thread, Worker, Volatile і Pool), а також як кожен із класів використовується. А ще ми глянули на нову концепцію незмінності в pthreads, зробили короткий огляд підтримуваних можливостей синхронізації. З цими основами, ми можемо тепер приступити до розгляду застосування pthreads у випадках реального світу! Це і буде темою нашого наступного посту.

Якщо вам цікавий переклад наступного посту, дайте знати: коментуйте у соц. мережах, плюсуйте та ділитесь постом з колегами та друзями.

Threaded discussion

A threaded discussionє електронна розмова (такий як один за допомогою електронної пошти , електронної пошти , повідомлень електронної пошти , newsgroup , або Internet forum) в якому програмне забезпечення використовується для користувача, використовуючи персоналізовані повідомлення. Messages є зазвичай grouped visually in a hierarchy by topic. Set set messages grouped in this way is called a topic threadабо simplly "thread". На дискусійному форумі, електронною поштою клієнта або новиною клієнта є доглядати за "трейдованими топіками", якщо його групи повідомлені на самій топічній картці разом з можливістю читання в цьому manner. Moreover, threaded discussions типово allow users to reply до особливих повідомлень within a topic"s thread. Як результат, there can be a hierarchy of discussions within thread topic. називається Threaded Mode. (Антенсивний стає Linear Mode, який типово зображений на всіх повідомленнях в межах терміну, незважаючи на те, що він має specifically replied to whom.)

Advantages

Відмінність hierarchically threaded views is that the allow the reader to appreciate quickly the overall structure of conversation: specifically who is replying to whom. Як це є найбільш можливим в роботі з розширеними розвідками або розмовами, такими як newsgroups: індеїд, для реально комплексної розмови, це стрімко стає неможливим до наступного argumentу без будь-якого sort hierarchical threading system in place.

Інший benefit is in more subtle appreciation of community in hierarchically threaded systems. Як responses have to be made to specific posts, they are also made to specific individuals. Запитання повідомлень єдля того, щоб розглянути повідомлення на конкретних переглядах і особистісності особистих речей. Цей випадок less in fora where latest comment is just inserted in the general pool.

Disadvantages

Відповідальність hierarchical threading over flat threading is increased level of complication, and such a view therefore requires increased level of comfort and sophistication on the part of its users. Це невідомо, що його придбання буде бути невідомим в деяких oldest і/або most sophisticated of online communities, так як Usenet , CIX or Slashdot . Web chat and comment systems are, by comparison, younger and open to a wider audience, and as such hierarchical threading is only recently becoming commonplace in such arenas.

Imposing a tree hierarchy і tends to fragment discussion within topic: it no longer becomes possible to post a message responding to or summarising several different previous posts. Instead, every previous post must be respond to individually. Це arguable те, що це тягнеться до більш суперечливого ділового стилю в тому, що використовує hierarchical threading. However, true though that may be, if a direct threaded reply is no longer possible due to volume of replies to the desired post, users are now often using quotes by person they are responding to in order to keep conversation on track and flowing smoothly. Це було зараховано до найбільшого повідомлення комунікації в тому випадку, що threading буде відповідати його іншимвирішення.

Open thread

На Open Thread refers to a blog post where readers мають коментарі і discuss any topic that they choose. Вони завжди мають багато useful on popular blogs with large amounts of traffic ; Вони будуть використані, коли власник blogу не має ніякого суб'єкта, щоб повідомити про те, або якщо є ull in posting.

Open threads є також використані для переміщення монотонів posts на головних сторінках blogs. Comments may build up on content-oriented posts; там, якщо користувачі використовуються в Open threads so page load times won"t be slowed down.

Examples

* Yahoo! Groups [ http://groups.yahoo.com/] , MSN Groups [ http://groups.msn.com/] and Slashdot [ http://www.slashdot.com/] Все з веб-основних forums that feature threaded discussions.

See also

* Scholarly Skywriting
* List of blogging terms

References

*Dartmouth. (2003). [ http://www.dartmouth.edu/~webteach/articles/discussion.html "Taking discussion online" ]
*Wolsey, T. DeVere, [ http://www.readingonline.org/Articles/Art_index.asp?]. "Reading Online", 7(4), January/February 2004. Retrieved December 30, 2007

Wikimedia Foundation. 2010 .

  • Leon Powe
  • Barh Azoum

Look at other dictionaries:

    Internet forum- phpBB Internet Forum software package, один з найбільш популярних forum packages ... Wikipedia

    History of virtual learning environments 1990s- У історії віртуальних навколишнього середовища, 1990-х років був зростанням, в першу чергу, щоб привести до повного комп'ютера і Internet.1990s1990* Formal Systems Inc. of Princeton, NJ, USA introduces a DOS заснований Assessment… … Wikipedia

    CoFFEE- Collaborative Face to Face Educational Environment Developer(s) LEAD consortium Stable release 5.0 / June 2010 Operating system Cross platform … Wikipedia

    Conversation threading- Це feature використовує багато електронних клієнтів, бюлетені boards, newsgroups, або Internet forums в яких програма електронної пошти використовується для користувача, використовуючи групові повідомлення. Messages є зазвичай grouped visually in a hierarchy by topic. A set of messages grouped… … Wikipedia

    Slashdot- Screenshot of Slashdot.org Головна сторінка URL slashdot.org Slogan News for nerds. Stuff that matters … Wikipedia

    MediaWiki- namespace redirects here. Для того, щоб зареєструвати MediaWiki namespace на Wikipedia, viz Help:MediaWiki namespace. Для загальної інформації про Wikipedia namespaces, viz Wikipedia:Namespace. Talk page and MediaWiki Talk page redirect here. For… … Wikipedia

    Computer-mediated communication- Для інших засобів, бачте CMC (disambiguation). Комп'ютерний mediated communication (CMC) є визначений як будь-який комунікаційний transaction, що висловлюються через використання двох або більше мережевих комп'ютерів. While the term has traditionally referred to those… … Wikipedia

    Comparison of wiki software- Наведені таблиці compare загальні та технічні відомості для числа wiki software packages. Contents 1 General information 2 Target audience 3 Features 1 4 Features 2 … Wikipedia

    Scholarly Skywriting- є терміном поєднаний з cognitive scientist Stevan Harnad describing combination of multiple email and topic threaded web archiv such as newsgroup, electronic mailing list, hypermail, netnews or Internet forum, linked and sortable by data, ... ... Wikipedia

    Collaborative decision-making software- Collaborative decision making (CDM) software є software application або module що coordinates the functions and features required to arrive at timely collective decision, enabling all relevant stakeholders to participate in the process. The… … Wikipedia

Іноді виникає необхідність виконувати кілька дій одночасно, наприклад, перевіряти зміни в одній таблиці БД і вносити модифікації в іншу. Причому якщо одна з операцій (наприклад, перевірка змін) займає багато часу, очевидно, що послідовне виконання не забезпечить балансування ресурсів.

Для вирішення такого роду завдань у програмуванні використовується багатопоточність - кожна операція міститься в окремий потік з виділеним обсягом ресурсів і працює всередині нього. За такого підходу всі завдання будуть виконуватися окремо і незалежно.

Хоча 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") ( find_another_one( );

Коли ми виконуємо цей скрипт без параметрів, він автоматично запускає дві копії себе з ідентифікаторами операцій ("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, що повертається функцією, ми орієнтуємося в якому потоці знаходимося в даний момент і виконуємо необхідні дії.



Подібні публікації