PHP має нарізку?


130

Я знайшов цей пакет PECL під назвою теми , але поки немає випуску. І нічого не з'являється на веб-сайті PHP.


Хтось знає, чи це ( pcntl_fork()) спрацює, якщо його дзвонять з Apache?
Джош К

Це неймовірно давно, але у мене є відповідь, яка фактично забезпечує введення в PHP (див. Нижче посилання).
Алек Ущелина

Вони рекомендують не дзвонити на вилку з серверного середовища. Я не звинувачую їх. Однак, pcntl_fork, здається, є найкращим рішенням для нарізки PHP.
just_wes

Так, вам не потрібно роздрібнювати файл php apache2.
andho

2
Використовувати pthreads працює як шарм
Baba

Відповіді:


40

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


1
Це те, що я думав. Я побачив купу старших дописів, які говорили "ні", і нічого на php.net, тому це була моя думка. Дякуємо, що підтвердили це.
Томас Оуенс

2
Так, цей пакет PECL є якоюсь дражницею - я також наткнувся на нього, але нічого з цього не вийшло.
Вілько

180

З посібника PHP для розширення pthreads :

pthreads - це об'єктно-орієнтований API, який дозволяє багатокористувацьку нитку в PHP. Він включає в себе всі інструменти, необхідні для створення багатопотокових програм, орієнтованих на Інтернет або консоль. PHP-програми можуть створювати, читати, писати, виконувати та синхронізувати з потоками, робочими та штабелями.

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

Перший випуск PHP4, 22 травня 2000 р., PHP постачався з безпечною архітектурою для потоків - способом для виконання декількох примірників інтерпретатора в окремих потоках у багатопотокових середовищах SAPI (Server API). Протягом останніх 13 років дизайн цієї архітектури був вдосконалений та вдосконалений: вона з часу використовує у виробництві на найбільших у світі веб-сайтах.

Нитки в землю користувачів ніколи не хвилювали команду PHP, і вона залишається такою і сьогодні. Ви повинні розуміти, що у світі, де PHP веде свою справу, існує вже визначений метод масштабування - додайте обладнання. Протягом багатьох років PHP існувало, апаратне забезпечення стало дешевше і дешевше, і це ставало все менше турбот для команди PHP. Поки вона дешевшала, вона також стала набагато потужнішою; сьогодні наші мобільні телефони та планшети мають двоярусну та чотирьохядерну архітектуру та багато оперативної пам’яті, яку ми можемо використовувати разом із цим, у наших настільних комп'ютерів та серверів зазвичай є 8 чи 16 ядер, 16 та 32 гігабайт оперативної пам’яті, хоча ми не завжди можемо мати дві в межах бюджету та наявності двох робочих столів рідко корисно для більшості з нас.

Крім того, PHP було написано для непрограміста, це багато любителів рідною мовою. Причина PHP настільки легко прийнята - це те, що вивчати та писати це легка мова. Причина PHP настільки надійна сьогодні в тому, що велика кількість роботи, яка входить в її розробку, і кожне окреме рішення, прийняте групою PHP. Його надійність і велична величина зберігають його в точковому світлі після всіх цих років; де його суперники впали в часі чи тиску.

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

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

pthreads для тих, хто бажає дослідити його, забезпечує API, який дозволяє користувачеві багатопотоково застосовувати PHP-програми. Його API - це вже незавершена робота, і він визначив бета-рівень стабільності та повноти.

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

pthreads використовує Posix Threads (навіть у Windows), що програміст створює - це реальні потоки виконання, але для того, щоб ці нитки були корисними, вони повинні знати про PHP - вміти виконувати код користувача, ділитися змінними та дозволити корисні засоби зв'язку (синхронізація). Отже, кожен потік створюється за допомогою екземпляра інтерпретатора, але, за задумом, його інтерпретатор ізольований від усіх інших примірників інтерпретатора - як і багатопотокові середовища API API. pthreads намагається подолати проміжок безпечним та безпечним способом. Багато проблем, що стосуються програміста потоків в C, просто не існують для програміста pthreads, за задумом pthreads - це копія при читанні та копіювання під час запису (оперативна пам'ять дешева), тому жоден екземпляр жодного разу не маніпулює одними і тими ж фізичними даними , але вони можуть впливати на дані в іншому потоці.

Навіщо копіювати на читати та копіювати на запис:

public function run() {
    ...
    (1) $this->data = $data;
    ...
    (2) $this->other = someOperation($this->data);
    ...
}

(3) echo preg_match($pattern, $replace, $thread->data);

(1) Поки блокування читання та запису зберігається у сховищі даних об'єктів pthreads, дані копіюються з оригінального місця в пам'яті до сховища об'єктів. pthreads не коригує перерахунок змінної, Zend здатний звільнити вихідні дані, якщо на нього немає подальших посилань.

(2) Аргумент до деякихOperation посилається на сховище об'єктів, оригінальні дані, що зберігаються, а це сама копія результату (1), знову копіюються для двигуна в контейнер zval, в той час як це відбувається блокування читання, утримується на магазин об'єктів, замок звільняється і двигун може виконувати функцію. Коли zval створено, він має коефіцієнт знижки 0, що дозволяє двигуну звільнити копію після завершення операції, оскільки інших посилань на неї не існує.

(3) Останній аргумент preg_match посилається на сховище даних, виходить блокування читання, набір даних у (1) копіюється в zval, знову зі знижкою 0. Замок звільнений, виклик до preg_match працює на копія даних, тобто сама копія вихідних даних.

Що потрібно знати:

  • Хеш-таблиця об’єктного магазину, де зберігаються дані, захищена потоками,
    заснована на TsHashTable, що постачається разом із PHP, Zend.

  • Магазин об'єктів має блокування читання і запису, для TsHashTable передбачено додаткове блокування доступу, таким чином, що при необхідності (і це робить, var_dump / print_r, прямий доступ до властивостей, оскільки двигун PHP хоче посилатися на них) pthreads може маніпулювати TsHashTable за межами визначеного API.

  • Блокування зберігаються лише під час операцій з копіювання, коли копії зроблені, блокування звільнені, у розумному порядку.

Це означає:

  • Коли відбувається запис, утримуються не тільки блокування читання і запису, але й додаткове блокування доступу. Сама таблиця заблокована, немає іншого способу, коли інший контекст може її заблокувати, прочитати, записати чи вплинути на неї.

  • Коли відбувається читання, утримується не тільки блокування читання, але й додатковий блокування доступу, знову ж таки таблиця заблокована.

Жоден два контексти не можуть фізично чи одночасно отримувати доступ до одних і тих же даних із об’єктного сховища, але записи, зроблені в будь-якому контексті з посиланням, впливатимуть на дані, прочитані в будь-якому контексті з посиланням.

Це архітектура, що розділяється нічим, і єдиний спосіб існування - це співіснування. Ті, хто трохи кмітливі, побачать, що тут робиться багато копіювання, і вони задумаються, чи це хороша річ. Досить багато копіювання триває протягом динамічного виконання, це динаміка динамічної мови. pthreads реалізується на рівні об'єкта, оскільки хороший контроль можна отримати над одним об’єктом, але методи - код, який програміст виконує - мають інший контекст, без блокування та копій - локальної області застосування методу. Об'єм об'єкта у випадку з об'єктом pthreads слід розглядати як спосіб обміну даними між контекстами, тобто це його мета. Зважаючи на це, ви можете скористатися прийомами, щоб уникнути блокування магазину об'єктів, якщо це не потрібно,

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

Кожен, хто працював у Java, побачить схожість між об'єктом pthreads та потоком в java; ці ж люди, без сумніву, побачать помилку під назвою ConcurrentModificationException - оскільки це звучить помилка, що виникає під час виконання Java, якщо два потоки записують однакові фізичні дані одночасно. Я розумію, чому вона існує, але мене бентежить, що ресурси, настільки дешеві, як і вони, в поєднанні з тим, що час виконання може виявити паралельність точно і єдиний час, коли безпека може бути досягнута для користувача, яку він вирішить кинути можливу фатальну помилку під час виконання, а не керувати виконанням та доступом до даних.

Жодних дурних помилок не буде випущено pthreads, API написано, щоб зробити нарізку максимально стабільною та сумісною, наскільки я вважаю.

Багатопотокове використання не схоже на використання нової бази даних, пильну увагу слід звертати на кожне слово в посібнику та приклади, що постачаються з pthreads.

Нарешті, з посібника PHP:

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


14
Повна дурниця.
Джо Уоткінс

7
@GeoC. Я навіть не впевнений, у чому тут твоя думка, це просто навантаження на безглуздість, і ти не наводиш жодних причин , логічних або інших питань, чому ти не згоден з жодними аргументами (про які я справді не можу бачити жодного в дописі) .
Jimbo

13
@Tudor Я не думаю, що ти насправді знаєш, про що ти говориш, тому я радий ігнорувати тебе.
Джо Уоткінс

4
@Tudor - багато вчених не «бачили сенсу» чогось нового у своїй галузі або чогось корисного. Історія показала, що найчастіше такі люди, як ти, просто помиляються, це факт. Так само, як і факт, що все, що ви тут написали, - це відсутність кращого слова, кал. Я настійно пропоную, маючи на увазі все позитивне, не брати участі в темах, про які ви нічого не знаєте (це одна).
NB

12
Смішна річ. Джо Уоткінс є автором pthreads, і досі Тудор намагається довести його неправильно.
Христо Валканов

48

Ось приклад того, що запропонував Вілко:

$cmd = 'nohup nice -n 10 /usr/bin/php -c /path/to/php.ini -f /path/to/php/file.php action=generate var1_id=23 var2_id=35 gen_id=535 > /path/to/log/file.log & echo $!';
$pid = shell_exec($cmd);

В основному це виконує скрипт PHP в командному рядку, але негайно повертає PID і потім працює у фоновому режимі. (Ехо $! Гарантує, що нічого іншого, окрім PID, не повертається.) Це дозволяє вашому PHP-скрипту продовжуватись або закриватися, якщо ви хочете. Використовуючи це, я перенаправляв користувача на іншу сторінку, де кожні 5 - 60 секунд робиться дзвінок AJAX, щоб перевірити, чи не працює звіт. (У мене є таблиця для зберігання gen_id та користувача, з яким він пов’язаний.) Сценарій перевірки працює наступним чином:

exec('ps ' . $pid , $processState);
if (count($processState) < 2) {
     // less than 2 rows in the ps, therefore report is complete
}

Тут є короткий пост про цю техніку: http://nsaunders.wordpress.com/2007/01/12/running-a-background-process-in-php/


У мене є невелика проблема, як у вас перевірити стан фонового процесу? можеш мене просвітити
slier

25

Коротше кажучи: так, у php є багатопотокова редакція, але замість цього слід використовувати багатопроцесорну роботу.

Інформація про груби: потоки та процеси

Завжди є невелика плутанина щодо розрізнення потоків і процесів, тому я коротко опишу:

  • А Потік являє собою послідовність команд , які будуть обробляти процесор. Єдині дані, з яких він складається, - це лічильник програм. Кожне ядро ​​процесора буде обробляти лише один потік за часом, але може перемикатися між виконанням різних за допомогою планування.
  • Процес являє собою набір загальних ресурсів. Це означає, що вона складається з частини пам’яті, змінних, примірників об’єктів, ручок файлів, мютексів, підключень до бази даних тощо. Кожен процес також містить одну або кілька потоків. Усі потоки одного процесу поділяють його ресурси, тому ви можете використовувати змінну в одному потоці, який ви створили в іншому. Якщо ці потоки є частинами двох різних процесів, вони не можуть отримати доступ до ресурсів один одного безпосередньо. У цьому випадку вам потрібно міжпроцесорне спілкування, наприклад, через труби, файли, розетки ...

Багатопроцесорна

Ви можете домогтися паралельних обчислень, створивши нові процеси (які також містять нову нитку) за допомогою php. Якщо вашим потокам не потрібна велика комунікація чи синхронізація, це ваш вибір, оскільки процеси є ізольованими і не можуть перешкоджати роботі один одного. Навіть якщо один врізається, це не стосується інших. Якщо вам потрібно багато спілкування, вам слід читати на "багатопотоковому" або, на жаль, розглянути можливість використання іншої мови програмування, оскільки міжпроцесовий зв'язок та синхронізація вводить багато складності.

У php у вас є два способи створити новий процес:

дозвольте ОС зробити це за вас : ви можете сказати вашій операційній системі створити новий процес і запустити в ньому новий (або той самий) скрипт php.

  • для Linux ви можете скористатися наступним або розглянути відповідь Дарріла Хайна :

    $cmd = 'nice php script.php 2>&1 & echo $!';
    pclose(popen($cmd, 'r'));
  • для Windows ви можете використовувати це:

    $cmd = 'start "processname" /MIN /belownormal cmd /c "script.php 2>&1"';
    pclose(popen($cmd, 'r'));

зробіть це самостійно за допомогою вилки : php також надає можливість використовувати розгортання через функцію pcntl_fork () . Хороший підручник про те, як це зробити, можна знайти тут, але я настійно рекомендую не користуватися ним, оскільки вилка - це злочин проти людства і особливо проти уп.

Багатопотоковість

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

Стандартний php не забезпечує багатопотокових читань, але є (експериментальне) розширення, яке насправді - pthreads . Його документація api навіть перетворила його на php.net . З його допомогою ви можете робити якісь речі на реальних мовах програмування :-), як це:

class MyThread extends Thread {
    public function run(){
        //do something time consuming
    }
}

$t = new MyThread();
if($t->start()){
    while($t->isRunning()){
        echo ".";
        usleep(100);
    }
    $t->join();
}

Для Linux є тут інструкція по встановленню в stackoverflow.

Зараз для вікон є:

  • Спочатку вам потрібна безпечна для потоків версія php.
  • Вам потрібні попередньо складені версії обох pthreads та його php розширення. Їх можна завантажити тут . Переконайтеся, що ви завантажите версію, сумісну з вашою версією php.
  • Скопіюйте php_pthreads.dll (із завантаженого вами поштового індексу) у папку розширення php ([phpDirectory] / ext).
  • Скопіюйте pthreadVC2.dll у [phpDirectory] (коренева папка - не папка розширення).
  • Відредагуйте [phpDirectory] /php.ini та вставте наступний рядок

    extension=php_pthreads.dll
  • Перевірте його за вищевказаним сценарієм, переночуючи сон чи щось там, де є коментар.

А тепер велике АЛЕ : Хоча це справді працює, php спочатку не був створений для багатопотокової роботи. Існує безпечна для потокової версії php, і на версію v5.4, здається, вона майже відсутня помилок, але використання php у багатопотоковому середовищі все ще не відмовляється в керівництві PHP (але, можливо, вони просто не оновлювали посібник на це, поки що). Набагато більша проблема може бути в тому, що багато поширених розширень не є безпечними для потоків . Таким чином, ви можете отримати теми з цим розширенням на php, але функції, від яких ви залежаєте, все ще не є безпечними для потоків, тому ви, мабуть, зіткнетесь з умовами перегонів, тупиками і т. Д. У коді, який ви самі не писали ...


5
Це жахливо неправильно, стаття, на яку ви посилаєтесь, виходить з 2008 року. Якби PHP не був безпечним для потоку в основі, він би не мав потокових SAPI модулів.
Джо Уоткінс

1
@Joe: Все гаразд, я змінив його в ядрі безпечно для потоків, але багато розширень - ні.
Франсуа Буржуа

1
Багато? Я думаю, ви знайдете його дуже мало, ви знайшли документацію, але не змогли її прочитати належним чином: Примітка: Ті, що позначені *, не є безпечними для потоків бібліотеками, і не повинні використовуватися з PHP як серверний модуль у мульти -потоковані веб-сервери Windows (IIS, Netscape). Це все ще не має значення в середовищі Unix.
Джо Уоткінс

6
PHP дуже безпечний для потоків, і це вже багато років, деякі зовнішні бібліотеки та кілька пакетних бібліотек не є, але це добре задокументовано, і все одно досить очевидно. pthreads створює нитки, які є настільки ж безпечними, як і нитки, створені zend у багатопотоковому сапі, я це знаю, тому що я один написав pthreads. Він використовує кожен доступний API, відкритий PHP так само, як це робить серверний API, я не кажу, що це повністю стабільно, але малюнок, який ви намалювали, просто невірний і дуже погано інформований.
Джо Уоткінс

@Joe: Коли інструкція говорить, що це не має значення для середовищ Unix, вони посилаються на те, що в системі Unix apache використовує кілька процесів, а в Windows використовує потоки. Тому в основному вони говорять: "Якщо ви все одно не використовуєте теми, вам не доведеться турбуватися про безпечні розширення, що не стосуються потоків". Коли ми використовуємо теми з pthreads, це, звичайно, має значення і в середовищі Unix.
Франсуа Буржуа

17

Ви можете використовувати pcntl_fork (), щоб досягти чогось подібного до потоків. Технічно це окремі процеси, тому зв’язок між ними не такий простий з потоками, і я вважаю, що це не спрацює, якщо PHP викликається apache.


4
Я успішно використовую pcntl_fork для паралелізації досить масового завдання імпорту даних. Чудово працює, і я працював приблизно за годину. Існує трохи кривої навчання, але як тільки ви зрозумієте, що відбувається, це досить прямо вперед.
Френк Фермер

Френк, це з CLI php або apache PHP?
Артем Русаковський

@Artem: Я теж хотів би знати.
Джош К

5
@Frank Farmer нас дражнить ... так само, як пакет PECL.
Роджер

1
Я використовував pcntl_fork з CLI. Я ніколи не пробував це в апачі; це звучить ризиковано. Навіть у CLI були деякі несподівані проблеми. У мене, здавалося, виникають проблеми, коли якщо одна дитина закрила обробку бази даних (бо вона закінчила свою роботу), вона також закрила з'єднання для братів і сестер. Оскільки діти є копіями батьків, підготуйтеся до дивацтва. З тих пір я переробив свій код, щоб просто породжувати нові, абсолютно окремі процеси через exec () - таким чином він чистіший.
Френк Фермер


7

pcntl_fork()це те, що ви шукаєте, але процес його розпалювання не врізається ниткою. тому у вас виникне проблема обміну даними. для їх вирішення можна скористатися функціями семафору phps ( http://www.php.net/manual/de/ref.sem.php ) черги повідомлень для початку можуть бути трохи простішими, ніж сегменти спільної пам'яті.

У будь-якому випадку, стратегія, яку я використовую у веб-рамках, яку я розробляю, яка завантажує ресурсомісткі блоки веб-сторінки (можливо, із зовнішніми запитами) паралельно: я роблю чергу на роботу, щоб знати, які дані я чекаю, а потім я розщеплюю поза робочими місцями для кожного процесу. Після завершення вони зберігають свої дані в кеш-пам'яті apc під унікальним ключем, до якого може отримати доступ батьківський процес. Після того, як всі дані є, це триває. я використовую простийusleep() чекати, оскільки міжпроцесовий зв’язок в апачі неможливий (діти втратять зв’язок з батьками і стануть зомбі ...). тож це підводить мене до останнього: важливо самостійно вбити кожну дитину! Є також класи, які розщеплюють процеси, але зберігають дані, я їх не вивчав, але zend Framework має один, і вони зазвичай роблять повільно, але надійно кодують. Ви можете знайти його тут: http://zendframework.com/manual/1.9/en/zendx.console.process.unix.overview.html Я думаю, вони використовують shm сегменти! ну і останнє, але не в останню чергу є помилка на цьому zend веб-сайті, незначна помилка в прикладі.

while ($process1->isRunning() && $process2->isRunning()) {
    sleep(1);
}
should of course be:
while ($process1->isRunning() || $process2->isRunning()) {
    sleep(1);
}



5

У мене є клас різьблення PHP, який бездоганно працює у виробничому середовищі вже понад два роки.

EDIT: Зараз це доступно як бібліотека композиторів і як частина моєї програми MVC, Hazaar MVC.

Дивіться: https://git.hazaarlabs.com/hazaar/hazaar-thread


Що робити, якщо, виходячи з вашого прикладу, програма у file.php, скажімо, наприклад, це дуже підтверджує наявність списку урисів 10k веб-сайту, а потім має зберегти результат у файлі CSV ... Чи буде цей файл написаний проблема?
Роджер

Підпроцес буде виконуватися тим самим користувачем, що і сценарій веб-сервера / батьків. Тому при написанні файлів у вас будуть такі ж міркування щодо дозволів, що і у звичайному режимі. Якщо у вас є проблеми з написанням файлів, спробуйте записати в / tmp і, коли це працює, перейдіть звідти.
Джеймі Карл

1
Посилання тепер мертве через редизайн, ви можете отримати його на машині зворотного зв'язку тут: web.archive.org/web/20130922043615/http://dev.funkynerd.com/…
Тоні

Додано до моєї бази MVC зараз. Дивіться: git.hazaarlabs.com/hazaar/hazaar-thread
Джеймі Карл


1

Коли-небудь чули про appserverтехнічний підрозділ?

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


-3

Існує досить незрозуміла, і незабаром її застаріла функція під назвою кліщі . Єдине, що я коли-небудь використовував, це дозволити скрипту захопити SIGKILL (Ctrl + C) і граціозно закрити.


3
Кліщі не виконують паралельно. По суті, після кожного твердження, функція галочки працює. Поки функція галочки працює, основний код не працює.
Френк Фермер

1
галочки потрібні лише для обробника сигналу ().
Нік
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.