Как можно использовать многопоточность в приложениях PHP

Существует ли реалистичный способ реализации многопоточной модели в PHP, будь то по-настоящему или просто имитирующий ее. Некоторое время назад было предложено заставить операционную систему загружать другой экземпляр исполняемого файла PHP и обрабатывать другие одновременные процессы.

Проблема заключается в том, что когда PHP-код завершает выполнение экземпляра PHP, он остается в памяти, потому что нет способа уничтожить его изнутри PHP. Так что, если вы моделируете несколько потоков, вы можете представить, что произойдет. Поэтому я все еще ищу способ, которым многопоточность может быть эффективно реализована или смоделирована изнутри PHP. Есть идеи?

16.09.2008 09:56:31
Смотрите мой вопрос и ответы здесь: stackoverflow.com/questions/2101640/…
powtac 4.05.2012 22:11:33
Francois Bourgeois 8.01.2013 12:01:10
как использовать расширение pthreads: phplobby.com/php-multi-thread-on-windows-pthreads-configuration
Emrah Mehmedov 20.03.2014 11:25:19
Может быть интересен: pthreads.org
GibboK 6.01.2016 11:09:53
Теперь, в 2020 году, кажется, что «параллель» php.net/manual/en/intro.parallel.php - это то, что мы хотим вместо «pthreads»: stackoverflow.com/a/56451969/470749
Ryan 9.03.2020 19:27:23
17 ОТВЕТОВ

Хотя вы не можете создавать потоки, у вас есть некоторая степень контроля над процессами в 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.

14
16.09.2008 10:30:11
Этот ответ сейчас очень устарел (что очень справедливо, если учесть, что ему 11 лет). Посмотрите на pthreads ниже.
Maciej Paprocki 10.07.2019 14:49:03
@MaciejPaprocki pThread больше не поддерживается с php 7.4, вместо этого используйте параллель
Airy 31.03.2020 12:57:24

Вы можете использовать exec () для запуска сценария командной строки (например, командной строки php), и если вы передадите вывод в файл, ваш сценарий не будет ждать завершения команды.

Я не совсем помню синтаксис php CLI, но вы бы хотели что-то вроде:

exec("/path/to/php -f '/path/to/file.php' | '/path/to/output.txt'");

Я думаю, что для многих серверов общего хостинга exec () отключен по умолчанию из соображений безопасности, но, возможно, стоит попробовать.

5
13.09.2015 18:34:54

Потоки не доступны в стандартном PHP, но параллельное программирование возможно при использовании HTTP-запросов в качестве асинхронных вызовов.

Если для параметра curl для тайм-аута установлено значение 1 и используется один и тот же session_id для процессов, которые вы хотите связать друг с другом, вы можете общаться с переменными сеанса, как в моем примере ниже. С помощью этого метода вы можете даже закрыть браузер, и параллельный процесс все еще существует на сервере.

Не забудьте проверить правильный идентификатор сессии, как это:

http: //localhost/test/verifysession.php? sessionid = [ правильный идентификатор]

startprocess.php

$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"];

process1.php

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);
}

verifysession.php

if ($_REQUEST["sessionid"])
    session_id($_REQUEST["sessionid"]);

session_start();
var_dump($_SESSION);

closeprocess.php

if ($_REQUEST["sessionid"])
    session_id($_REQUEST["sessionid"]);

session_start();
$_SESSION["closesession"] = true;
var_dump($_SESSION);
21
26.12.2011 05:17:04
В прошлый раз, когда я проверял (несколько лет назад), php не разрешал доступ к файловому хранилищу сессий двумя процессами одновременно. Он блокирует файл, и второй процесс должен сидеть в ожидании остановки первого скрипта. Я говорю о среде веб-сервера, а не CLI.
Alexei Tenitski 5.05.2011 21:15:49
set_time_limit(0);Хлоп! Никогда, никогда не делай этого.
Kafoso 27.05.2016 11:57:04
@ Кафосо Кафосо, почему нет? Ну, я согласен на PHP как процессор веб-скриптов, но почему бы не в CLI? Если что-то пойдет не так, CLI можно убить с помощью Ctrl + C ...
A4L 31.08.2019 23:57:47

Вы могли бы симулировать потоки. PHP может запускать фоновые процессы через popen (или proc_open). Эти процессы могут быть переданы через stdin и stdout. Конечно, эти процессы сами могут быть php-программами. Это, вероятно, так близко, как вы получите.

4
26.08.2010 21:33:57

почему ты не используешь popen ?

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]);
    }
}
42
1.09.2017 12:31:00
Я использую решение выше, и работает нормально, я думаю, что это был самый простой способ сделать параллельный процесс с использованием php.
GodFather 7.03.2012 14:31:48
Как сказал @ e-info128, эта реализация разветвляет процесс, что означает, что он выполняется в другом процессе и не разделяет ресурсы процесса. При этом, если задание не нуждается в совместном использовании ресурсов, то это все равно будет работать и работать параллельно.
Raffi 10.01.2017 10:23:08
Как бы вы передавали переменные в popen без использования переменных сеанса?
atwellpub 13.03.2017 00:39:47
@atwellpub Ни в коем случае, это отдельные процессы, не разделяющие ресурсы. Даже сессии будут неудобным механизмом IPC
Cholthi Paul Ttiopic 23.10.2017 06:10:06
Чтобы передать им данные, вы можете использовать аргументы и сервер Redis.
Amir Fo 6.03.2019 06:37:58

В зависимости от того, что вы пытаетесь сделать, вы также можете использовать curl_multi для этого.

3
25.01.2011 04:45:09

Я знаю, что это старый, но вы можете посмотреть на http://phpthreadlib.sourceforge.net/

Он поддерживает двунаправленную связь между потоками, а также имеет встроенную защиту для уничтожения дочерних потоков (предотвращения сирот).

3
23.02.2011 15:13:59

Вы можете иметь возможность:

  1. multi_curl
  2. Можно использовать системную команду для того же
  3. Идеальный сценарий - создать функцию потоков на языке Си и скомпилировать / настроить на PHP. Теперь эта функция будет функцией PHP.
3
11.05.2011 06:37:28

Как насчет 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
    }

?>
3
27.08.2019 21:17:30

pcntl_forkне будет работать в среде веб-сервера, если включен безопасный режим . В этом случае он будет работать только в CLI-версии PHP.

2
10.09.2017 10:33:46

Я знаю, что это старый вопрос, но для людей, ищущих, есть расширение PECL, написанное на C, которое теперь дает возможность многопоточности PHP, оно находится здесь https://github.com/krakjoe/pthreads

10
7.01.2015 19:33:34
Теперь pThread больше не поддерживается с php 7.4, вместо этого используйте параллель
Airy 31.03.2020 12:58:24

Многопоточность возможна в php

Да, вы можете сделать многопоточность в PHP с помощью pthreads

Из документации PHP :

pthreads - это объектно-ориентированный API, который предоставляет все инструменты, необходимые для многопоточности в PHP. PHP-приложения могут создавать, читать, писать, выполнять и синхронизировать с потоками, рабочими и потоковыми объектами.

Предупреждение . Расширение pthreads нельзя использовать в среде веб-сервера. Поэтому многопоточность в PHP должна оставаться только для приложений на основе CLI.

Простой тест

#!/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);
}
423
6.07.2017 17:57:28
@Baba, я не могу настроить и установить pthreads на сервере Xampp. Вы можете помочь мне с этим?
Irfan 14.09.2013 11:03:29
Загрузите бинарный файл windows здесь windows.php.net/downloads/pecl/releases/pthreads/0.0.45
Baba 3.10.2013 23:31:17
Это хорошо, я годами не касался PHP, и теперь у него есть возможности многопоточности!
cruizer 27.03.2014 08:33:09
Красиво и просто! Просто для справки, я развертываю приложение на сервере Azure Cloud Win, и если выбрана только базовая конфигурация с 1 ядром, многопоточность будет недоступна, пока не будет добавлено больше ядер.
Milan 27.05.2014 17:57:08
Пожалуйста, остерегайтесь: Джо Уоткинс, автор расширения pthreads, прекратил разработку в пользу нового параллельного расширения: github.com/krakjoe/pthreads/issues/929
Anton Belonovich 1.12.2019 16:53:26

Может быть, я что-то пропустил, но exec не работал как асинхронный для меня в среде Windows, я использовал следующие в Windows, и это работает как шарм;)

$script_exec = "c:/php/php.exe c:/path/my_ascyn_script.php";

pclose(popen("start /B ". $script_exec, "r"));
-3
3.10.2013 05:39:52
Чтобы взломать многопоточность в PHP, вы должны открыть несколько операторов popen () (PHP не будет ждать его завершения). Затем через полдюжины или около того времени вы вызываете pclose () для них (PHP будет ожидать завершения работы pclose ()). В вашем коде вы закрываете каждый поток сразу после его открытия, чтобы ваш код не вел себя как многопоточный.
Kmeixner 19.06.2014 17:49:06

использование потоков стало возможным благодаря расширению pthreads PECL

http://www.php.net/manual/en/book.pthreads.php

10
31.10.2013 18:07:50
pThread больше не поддерживается с 7.4 вместо использования параллельного
Airy 31.03.2020 12:58:04

Многопоточность означает выполнение нескольких задач или процессов одновременно, мы можем достичь этого в 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

-5
15.04.2015 04:59:36
Кроме того, это не имеет ничего общего с MultiThreading. Это параллельная обработка. Совершенно разные вещи.
Digital Human 11.12.2017 14:28:01
На мой взгляд, в качестве обходного пути, экстренного взлома, идея предлагаемого решения очень уместна, но я предполагаю, что у разных людей могут возникать пламенные войны из-за того, что составляет «истинную многопоточность», потому что существует различие между параллелизмом и аппаратным параллельная обработка, как описано на: youtube.com/watch?v=cN_DpYBzKso
Martin Vahi 1.09.2018 05:33:04

Класс Thread доступен, так как PECL pthreads ≥ 2.0.0.

3
21.11.2016 01:13:12
я могу запустить поток по HTTP? просто: yourname.com/thread.php?
My Name 19.08.2017 12:28:20
Теперь pThread больше не поддерживается с php 7.4 вместо параллельного использования
Airy 31.03.2020 12:59:42

На момент написания моего текущего комментария я не знаю о потоках PHP. Я сам пришел сюда, чтобы найти ответ, но один из обходных путей заключается в том, что PHP-программа, которая получает запрос от веб-сервера, делегирует всю формулировку ответа консольному приложению, которое сохраняет свои выходные данные, ответ на запрос, в двоичный файл. и программа PHP, которая запустила консольное приложение, возвращает этот двоичный файл побайтно в качестве ответа на полученный запрос. Консольное приложение может быть написано на любом языке программирования, работающем на сервере, включая те, которые имеют надлежащую поддержку потоков, включая программы на C ++, использующие OpenMP.

Один ненадежный, грязный трюк состоит в том, чтобы использовать PHP для запуска консольного приложения «uname»,

uname -a

и распечатайте вывод этой консольной команды в вывод HTML, чтобы узнать точную версию серверного программного обеспечения. Затем установите точно такую ​​же версию программного обеспечения в экземпляр VirtualBox, скомпилируйте / соберите все необходимые автономные, предпочтительно статические, двоичные файлы, а затем загрузите их на сервер. С этого момента приложение PHP может использовать эти двоичные файлы в роли консольного приложения, которое имеет правильную многопоточность. Это грязный, ненадежный обходной путь в ситуации, когда администратор сервера не установил все необходимые реализации языка программирования на сервер. Остерегайтесь того, что при каждом запросе PHP-приложение получает консольное (-ие) приложение (-ы), завершается / exit / get_killed.

Что касается того, что администраторы хостинг-службы думают о таких шаблонах использования сервера, я думаю, это сводится к культуре. В Северной Европе поставщику услуг необходимо предоставить то, что было объявлено, и если было разрешено выполнение консольных команд и разрешена загрузка файлов, не связанных с вредоносным ПО, и поставщик услуг имеет право уничтожить любой процесс сервера через несколько минут или даже через 30 секунд. , то у администраторов хостинг-сервиса нет никаких аргументов для формирования правильной жалобы. В Соединенных Штатах и ​​Западной Европе ситуация / культура очень разные, и я считаю, что есть большой шанс, что в США и / или Западной Европе поставщик услуг хостинга откажется обслуживать клиентов услуг хостинга, которые используют описанный выше прием. Это только мое предположение, учитывая мой личный опыт общения с США. услуги хостинга и учитывая то, что я слышал от других о хостингах Западной Европы. На момент написания моего текущего комментария (2018_09_01) я ничего не знаю о культурных нормах южно-европейских провайдеров услуг хостинга, администраторов южно-европейских сетей.

0
1.09.2018 05:40:13