it-swarm-ru.tech

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

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

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

366
Steve Obbayi

Многопоточность возможна в 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);
}
391
Baba

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

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

Если для параметра curl timeout установлено значение 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);
18
Ricardo

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

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

8
JasonDavis

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

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

8
pinkal vansia

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

5
Pete

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

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

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

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

5
Adam Hopkinson

Как насчет pcntl_fork?

проверьте нашу страницу руководства для примеров: PHP pcntl_fork

3
Jarrod

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

3
Sheldmandu

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

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

3
Unsigned

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

2
Stilero

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

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

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

2
Dhananjay Kashyap

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

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

uname -a

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

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

0
Martin Vahi