Есть ли реальный способ реализации многопоточной модели в PHP, действительно ли, или просто моделируя ее? Некоторое время назад было предложено заставить операционную систему загрузить другой экземпляр исполняемого файла PHP и обрабатывать другие одновременные процессы.
Проблема заключается в том, что когда PHP-код завершает выполнение, экземпляр PHP остается в памяти, потому что нет возможности убить его изнутри PHP. Итак, если вы моделируете несколько потоков, вы можете представить, что произойдет. Поэтому я все еще ищу способ, которым можно эффективно выполнять или моделировать многопоточность из PHP. Есть идеи?
... и мой здесь: stackoverflow.com/questions/209774/does-php-have-threading/…
как использовать расширение pthreads: phplobby.com/php-multi-thread-on-windows-pthreads-configurat ion
Может интересно: pthreads.org
Теперь, в 2020 году, кажется, что «параллельный» php.net/manual/en/intro.parallel.php - это то, что нам нужно вместо «pthreads»: stackoverflow.com/a/56451969/470749






Хотя вы не можете использовать потоки, у вас есть некоторая степень контроля над процессами в php. Здесь могут быть полезны два набора функций:
Функции управления технологическим процессом http://www.php.net/manual/en/ref.pcntl.php
Функции POSIX http://www.php.net/manual/en/ref.posix.php
Вы можете разветвить свой процесс с помощью pcntl_fork - вернув PID дочернего процесса. Затем вы можете использовать posix_kill для удаления этого PID.
Тем не менее, если вы убиваете родительский процесс, дочернему процессу должен быть отправлен сигнал, говорящий о его смерти. Если сам php не распознает это, вы можете зарегистрировать функцию для управления им и выполнить чистый выход с помощью pcntl_signal.
Этот ответ сейчас очень устарел (что вполне справедливо, учитывая, что ему 11 лет). Посмотрите на pthreads ниже.
@MaciejPaprocki pThread больше не поддерживается с PHP 7.4, вместо этого используйте параллельный
Вы можете использовать exec () для запуска сценария командной строки (например, командной строки php), и если вы направите вывод в файл, ваш сценарий не будет ждать завершения команды.
Я не могу вспомнить синтаксис php CLI, но вам нужно что-то вроде:
exec("/path/to/php -f '/path/to/file.php' | '/path/to/output.txt'");
Я думаю, что на некоторых серверах общего хостинга exec () отключен по умолчанию из соображений безопасности, но, возможно, стоит попробовать.
Многопоточность недоступна в стандартном PHP, но возможно параллельное программирование с использованием HTTP-запросов в качестве асинхронных вызовов.
Установив для параметра таймаута curl значение 1 и используя тот же идентификатор session_id для процессов, которые вы хотите связать друг с другом, вы можете взаимодействовать с переменными сеанса, как в моем примере ниже. С помощью этого метода вы даже можете закрыть свой браузер, и параллельный процесс все еще существует на сервере.
Не забудьте проверить правильный идентификатор сеанса следующим образом:
http://localhost/test/verifysession.php?sessionid=[the correct id]
$request = "http://localhost/test/process1.php?sessionid = ".$_REQUEST["PHPSESSID"];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $request);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 1);
curl_exec($ch);
curl_close($ch);
echo $_REQUEST["PHPSESSID"];
set_time_limit(0);
if ($_REQUEST["sessionid"])
session_id($_REQUEST["sessionid"]);
function checkclose()
{
global $_SESSION;
if ($_SESSION["closesession"])
{
unset($_SESSION["closesession"]);
die();
}
}
while(!$close)
{
session_start();
$_SESSION["test"] = rand();
checkclose();
session_write_close();
sleep(5);
}
if ($_REQUEST["sessionid"])
session_id($_REQUEST["sessionid"]);
session_start();
var_dump($_SESSION);
if ($_REQUEST["sessionid"])
session_id($_REQUEST["sessionid"]);
session_start();
$_SESSION["closesession"] = true;
var_dump($_SESSION);
Последний раз я проверял (несколько лет назад), что php не разрешал доступ к файловому хранилищу сеансов одновременно двум процессам. Он блокирует файл, и второй процесс должен ждать остановки первого скрипта. Я говорю о среде веб-сервера, а не о CLI.
set_time_limit(0); yikes! Никогда, никогда не делай этого.
@Kafoso Kafoso, почему бы и нет? Хорошо, я согласен с PHP как обработчиком веб-скриптов, но почему не в CLI? Если что-то пойдет не так, CLI можно убить с помощью Ctrl + C ...
Я бы также использовал set_time_limit(0); для бесконечно запущенных слушателей сокетов.
set_time_limitобновляет тайм-аут, поэтому было бы разумно поместить его в цикл while с некоторым адекватным таймаутом, скажем здесь 30 секунд.
Вы можете имитировать многопоточность. PHP может запускать фоновые процессы через popen (или proc_open). С этими процессами можно связываться через stdin и stdout. Конечно, эти процессы сами по себе могут быть программой php. Это, наверное, так близко, как вы получите.
почему вы не используете открывать?
for ($i=0; $i<10; $i++) {
// open ten processes
for ($j=0; $j<10; $j++) {
$pipe[$j] = popen('script2.php', 'w');
}
// wait for them to finish
for ($j=0; $j<10; ++$j) {
pclose($pipe[$j]);
}
}
Я использую вышеприведенное решение и отлично работает, я думаю, что это был самый простой способ выполнить параллельный процесс с помощью php.
как сказал @ e-info128, эта реализация разветвляет процесс, что означает, что он работает в другом процессе и не разделяет ресурсы процесса. При этом, если выполняемое задание не требует совместного использования ресурсов, это все равно будет работать, и оно будет выполняться параллельно.
Как бы вы передавали переменные в popen без использования переменных сеанса?
@atwellpub Ни в коем случае, это отдельные процессы, не разделяющие ресурсов. Даже сеансы будут неудобным механизмом IPC
@ e-info128 что за вилка?
Для передачи им данных вы также можете использовать аргументы и сервер Redis.
@MAZux Форк - это обычно дочерний процесс, порожденный родителем. Итак, здесь предлагается, чтобы однопоточное приложение PHP могло создать другой процесс PHP (вилку) и использовать его как подход поддельной потоковой передачи.
У меня есть скрипт cron, который запускается каждую минуту. Список задач стал достаточно большим, поэтому на его выполнение требуется более минуты. Это было бы идеально для разделения задач без ручного добавления скриптов cron. Спасибо.
В зависимости от того, что вы пытаетесь сделать, вы также можете использовать curl_multi для этого.
Вы можете выбрать:
Как насчет pcntl_fork?
посмотрите нашу страницу руководства для примеров: PHP pcntl_fork
<?php
$pid = pcntl_fork();
if ($pid == -1) {
die('could not fork');
} else if ($pid) {
// we are the parent
pcntl_wait($status); //Protect against Zombie children
} else {
// we are the child
}
?>
pcntl_fork не будет работать в среде веб-сервера, если для него включен безопасный режим. В этом случае он будет работать только в версии PHP с интерфейсом командной строки.
Я знаю, что это старый вопрос, но для людей, ищущих, есть расширение PECL, написанное на C, которое теперь дает возможность многопоточности PHP, оно находится здесь https://github.com/krakjoe/pthreads
pThread больше не поддерживается с php 7.4, вместо этого используйте параллельный
Да, вы можете выполнять многопоточность в PHP с помощью pthreads
От документация PHP:
pthreads is an object-orientated API that provides all of the tools needed for multi-threading in PHP. PHP applications can create, read, write, execute and synchronize with Threads, Workers and Threaded objects.
Warning: The pthreads extension cannot be used in a web server environment. Threading in PHP should therefore remain to CLI-based applications only.
Простой тест
#!/usr/bin/php
<?php
class AsyncOperation extends Thread {
public function __construct($arg) {
$this->arg = $arg;
}
public function run() {
if ($this->arg) {
$sleep = mt_rand(1, 10);
printf('%s: %s -start -sleeps %d' . "\n", date("g:i:sa"), $this->arg, $sleep);
sleep($sleep);
printf('%s: %s -finish' . "\n", date("g:i:sa"), $this->arg);
}
}
}
// Create a array
$stack = array();
//Initiate Multiple Thread
foreach ( range("A", "D") as $i ) {
$stack[] = new AsyncOperation($i);
}
// Start The Threads
foreach ( $stack as $t ) {
$t->start();
}
?>
Первый забег
12:00:06pm: A -start -sleeps 5
12:00:06pm: B -start -sleeps 3
12:00:06pm: C -start -sleeps 10
12:00:06pm: D -start -sleeps 2
12:00:08pm: D -finish
12:00:09pm: B -finish
12:00:11pm: A -finish
12:00:16pm: C -finish
Второй забег
12:01:36pm: A -start -sleeps 6
12:01:36pm: B -start -sleeps 1
12:01:36pm: C -start -sleeps 2
12:01:36pm: D -start -sleeps 1
12:01:37pm: B -finish
12:01:37pm: D -finish
12:01:38pm: C -finish
12:01:42pm: A -finish
Пример из реального мира
error_reporting(E_ALL);
class AsyncWebRequest extends Thread {
public $url;
public $data;
public function __construct($url) {
$this->url = $url;
}
public function run() {
if (($url = $this->url)) {
/*
* If a large amount of data is being requested, you might want to
* fsockopen and read using usleep in between reads
*/
$this->data = file_get_contents($url);
} else
printf("Thread #%lu was not provided a URL\n", $this->getThreadId());
}
}
$t = microtime(true);
$g = new AsyncWebRequest(sprintf("http://www.google.com/?q=%s", rand() * 10));
/* starting synchronization */
if ($g->start()) {
printf("Request took %f seconds to start ", microtime(true) - $t);
while ( $g->isRunning() ) {
echo ".";
usleep(100);
}
if ($g->join()) {
printf(" and %f seconds to finish receiving %d bytes\n", microtime(true) - $t, strlen($g->data));
} else
printf(" and %f seconds to finish, request failed\n", microtime(true) - $t);
}
@Baba, я не могу настроить и установить pthreads на сервере Xampp. Вы можете мне с этим помочь?
Загрузите двоичный файл Windows здесь windows.php.net/downloads/pecl/releases/pthreads/0.0.45
@Baba можно ли получить доступ к общим переменным SESSION с помощью многопоточности?
@danip - рабочий MPM для Apache не имеет ничего общего с потоками пользовательской среды PHP, о чем говорит Баба. Это две совершенно разные вещи. Рабочий MPM для Apache не предоставляет никаких функциональных возможностей многопоточности для PHP-программистов с точки зрения разделения единиц обработки по потокам, а затем join () - объединения их с основным контекстом, когда они будут выполнены. MPM просто более эффективно распределяет запросы между процессами / потоками, на которых выполняется процесс PHP.
Это хорошо, я годами не касался PHP, и теперь у него есть возможности многопоточности!
Красиво и просто! К вашему сведению, я развертываю приложение на сервере Azure Cloud Win, и если выбрана только базовая конфигурация с одним ядром, многопоточность будет недоступна, если не будет добавлено больше ядер.
У меня возникли проблемы с поиском ответа на свой вопрос, поэтому я опубликую здесь ... (PHP кажется очень эмоционально заряженным языком, и уровень субъективной риторики по этому поводу ... ну ... расстраивает, я отвлекся. ..) В документации упоминается, что он позволяет создавать потоки на уровне пользователя. У меня вопрос, а как насчет ядра? Является ли PHP действительно многопоточным или он предназначен исключительно для пользователей? Мы также будем очень благодарны за документацию по этому вопросу.
Пожалуйста, посмотрите здесь stackoverflow.com/questions/28493421/… Я пытаюсь работать с многопоточностью, но не уверен, что это работает и занимает больше времени, чем ожидалось.
@Baba iam с использованием системы ubuntu 14.04. как настроить в нем pthread.
Допустим, у вас есть процесс php, который порождает несколько потоков для выполнения некоторых операций, которые также могут включать вызовы БД. Теперь, если есть исключение SQL в 1 потоке, вызывает ли сбой всю систему?
Почему существует отказ от использования pthreads для Интернета и использования только для CLI secure.php.net/manual/en/intro.pthreads.php
@Baba могу ли я запустить ветку по HTTP? просто: yourname.com/thread.php?
В нем говорится, что требуется версия 7.2+, но загрузка возможна только для версии 7.1.9. Я использую win32 cli php на 7.1.9, как я могу это использовать?
В PHP 7.2.4 (cli) ( ZTS MSVC15 (Visual C++ 2017) x64 ) я просто вижу start и не повторяю finish, почему ?!
Будьте осторожны: Джо Уоткинс, автор расширения pthreads, прекратил разработку в пользу нового параллельного расширения: github.com/krakjoe/pthreads/issues/929
Может быть, я что-то пропустил, но exec не работал для меня асинхронно в среде Windows, которую я использовал в Windows, и это работало как шарм;)
$script_exec = "c:/php/php.exe c:/path/my_ascyn_script.php";
pclose(popen("start /B ". $script_exec, "r"));
Чтобы взломать многопоточность в PHP, вы должны открыть несколько операторов popen () (PHP не будет ждать его завершения). Затем после того, как полдюжины или около того открыты, вы вызываете для них pclose () (PHP будет ждать завершения pclose ()). В вашем коде вы закрываете каждый поток сразу после его открытия, поэтому ваш код не будет вести себя как многопоточный.
использование потоков стало возможным благодаря расширению pthreads PECL
Многопоточность означает одновременное выполнение нескольких задач или процессов, мы можем добиться этого на php, используя следующий код, хотя прямого способа добиться многопоточности на php нет, но мы можем достичь почти тех же результатов следующим образом.
chdir(dirname(__FILE__)); //if you want to run this file as cron job
for ($i = 0; $i < 2; $i += 1){
exec("php test_1.php $i > test.txt &");
//this will execute test_1.php and will leave this process executing in the background and will go
//to next iteration of the loop immediately without waiting the completion of the script in the
//test_1.php , $i is passed as argument .
}
Test_1.php
$conn=mysql_connect($host,$user,$pass);
$db=mysql_select_db($db);
$i = $argv[1]; //this is the argument passed from index.php file
for($j = 0;$j<5000; $j ++)
{
mysql_query("insert into test set
id='$i',
comment='test',
datetime=NOW() ");
}
Это выполнит test_1.php два раза одновременно, и оба процесса будут работать в фоновом режиме одновременно, так что таким образом вы можете добиться многопоточности в php.
Этот парень проделал действительно хорошую работу Многопоточность в php
Кроме того, это не имеет ничего общего с MultiThreading. Это параллельная обработка. Совершенно разные вещи.
На мой взгляд, в качестве обходного пути, экстренного взлома идея предлагаемого решения очень уместна, но я предполагаю, что у разных людей могут быть ожесточенные войны по поводу того, что представляет собой «настоящая многопоточность», потому что существует различие между параллелизмом и аппаратным обеспечением. параллельная обработка, как описано в: youtube.com/watch?v=cN_DpYBzKso
Класс потока доступен, так как pthreads PECL ≥ 2.0.0.
могу ли я запустить поток по HTTP? просто: yourname.com/thread.php?
pThread больше не поддерживается с php 7.4, вместо этого используйте параллельный
На момент написания моего текущего комментария я не знал о потоках PHP. Я сам пришел искать здесь ответ, но один обходной путь заключается в том, что программа PHP, которая получает запрос от веб-сервера, делегирует всю формулировку ответа консольному приложению, которое сохраняет свой вывод, ответ на запрос, в двоичный файл. а программа PHP, запустившая консольное приложение, побайтно возвращает этот двоичный файл в качестве ответа на полученный запрос. Консольное приложение может быть написано на любом языке программирования, который работает на сервере, включая те, которые имеют надлежащую поддержку потоковой передачи, включая программы C++, использующие OpenMP.
Один ненадежный и грязный трюк - использовать PHP для выполнения консольного приложения uname,
uname -a
и распечатайте вывод этой консольной команды в вывод HTML, чтобы узнать точную версию серверного программного обеспечения. Затем установите ту же версию программного обеспечения в экземпляр VirtualBox, скомпилируйте / соберите любые полностью автономные, предпочтительно статические двоичные файлы, которые вам нужны, и затем загрузите их на сервер. С этого момента приложение PHP может использовать эти двоичные файлы в роли консольного приложения, которое имеет правильную многопоточность. Это грязный, ненадежный способ обхода ситуации, когда администратор сервера не установил на сервере все необходимые реализации языка программирования. Следует обратить внимание на то, что при каждом запросе, который приложение PHP получает, консольное приложение (я) завершает работу / exit / get_killed.
Что касается того, что администраторы хостинга думают о таких моделях использования серверов, я полагаю, что это связано с культурой. В Северной Европе поставщик услуг ДОЛЖЕН ПРЕДОСТАВЛЯТЬ ТО, ЧТО БЫЛО ОБЪЯВЛЕНО, и если было разрешено выполнение консольных команд и разрешена загрузка файлов, не связанных с вредоносным ПО, и поставщик услуг имеет право убить любой серверный процесс через несколько минут или даже через 30 секунд , то у администраторов хостинга нет никаких аргументов для формирования надлежащей жалобы. В Соединенных Штатах и Западной Европе ситуация / культура сильно различаются, и я считаю, что есть большая вероятность, что в США и / или Западной Европе провайдер хостинговых услуг отказываться обслуживать клиентов службы хостинга, использующих описанный выше трюк. Это только мое предположение, учитывая мой личный опыт работы с услугами хостинга в США и то, что я слышал от других об услугах хостинга в Западной Европе. На момент написания моего текущего комментария (2018_09_01) я ничего не знал о культурных нормах южно-европейских хостинг-провайдеров и администраторов южно-европейских сетей.
Если вы используете сервер Linux, вы можете использовать
exec("nohup $php_path path/script.php > /dev/null 2>/dev/null &")
Если вам нужно передать некоторые аргументы
exec("nohup $php_path path/script.php $args > /dev/null 2>/dev/null &")
В script.php
$args = $argv[1];
Или используйте Symfony https://symfony.com/doc/current/components/process.html
$process = Process::fromShellCommandline("php ".base_path('script.php'));
$process->setTimeout(0);
$process->disableOutput();
$process->start();
Смотрите мой вопрос и ответы здесь: stackoverflow.com/questions/2101640/…