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

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

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

Ответ 1

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

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

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

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

Внимание: Расширение pthreads нельзя использовать в среде веб-сервера. Поэтому Threading в 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);
}

Ответ 2

почему вы не используете 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]);
    }
}

Ответ 3

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

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

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

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

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

Ответ 4

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

Ответ 6

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

Ответ 7

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

Я не могу полностью запомнить синтаксис CLI php, но вам нужно что-то вроде:

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

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

Ответ 8

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

Ответ 9

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

?>

Ответ 10

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

Ответ 11

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

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

Ответ 12

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

Ответ 13

У вас может быть опция:

  • multi_curl
  • Можно использовать системную команду для того же
  • Идеальный сценарий - создание функции потоковой передачи на языке C и компиляция/настройка в PHP. Теперь эта функция будет функцией PHP.

Ответ 14

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

Ответ 16

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

Один ненадежный, грязный, трюк - использовать PHP для выполнения консольного приложения, "uname",

uname -a

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

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

Ответ 17

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

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

pclose(popen("start /B ". $script_exec, "r"));

Ответ 18

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