it-swarm-eu.dev

Jak lze použít vícevláknové zpracování v aplikacích PHP

Existuje realistický způsob implementace modelu s více vlákny v PHP, ať už je to skutečně, nebo jen simulace. Někdy zpět bylo navrženo, že byste mohli donutit operační systém načíst další instanci spustitelného souboru PHP a zpracovat další simultánní procesy.

Problém je v tom, že když kód PHP skončil vykonáním instance PHP, zůstává v paměti, protože v PHP neexistuje způsob, jak jej zabít. Pokud tedy simulujete několik vláken, můžete si představit, co se stane. Stále tedy hledám způsob, jak lze pomocí podprocesu PHP efektivně provádět nebo simulovat vícevláknové procesy. Nějaké nápady?

366
Steve Obbayi

Vícevláknové je možné v php

Ano, můžete provádět více vláken v PHP s pthreads

Z dokumentace PHP :

pthreads je objektově orientované API, které poskytuje všechny nástroje potřebné pro vícevláknové zpracování v PHP. PHP aplikace mohou vytvářet, číst, psát, spouštět a synchronizovat s Threads, Workers a Threaded objects.

Upozornění : Rozšíření pthreads nelze použít v prostředí webového serveru. Vlákna v PHP by proto měla zůstat pouze pro aplikace založené na CLI.

Jednoduchý test

#!/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();
}

?>

První běh

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

Druhý běh

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

Příklad reálného světa

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

proč nepoužíváte 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

Vlákno není dostupné na skladě PHP, ale současné programování je možné pomocí HTTP požadavků jako asynchronních volání.

S nastavením časového limitu curl na 1 a pomocí stejné session_id pro procesy, které chcete být spojeny s sebou, můžete komunikovat s proměnnými relace jako v mém příkladu níže. S touto metodou můžete dokonce zavřít prohlížeč a souběžný proces na serveru stále existuje.

Nezapomeňte ověřit správné ID relace takto:

http: //localhost/test/verifysession.php? sessionid = [the správné id]

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

I když nemůžete vláknit, máte určitý stupeň řízení procesů v php. Zde jsou užitečné dvě sady funkcí:

Funkce řízení procesů http://www.php.net/manual/en/ref.pcntl.php

Funkce POSIX http://www.php.net/manual/en/ref.posix.php

Mohli byste rozvětvit svůj proces pomocí pcntl_fork - vrácení PID dítěte. Pak můžete použít posix_kill k popisu tohoto PID.

To znamená, že pokud zabijete rodičovský proces, měl by být odeslán signál do dětského procesu, který mu říká, aby zemřel. Pokud to php sám neuznává, můžete zaregistrovat funkci pro správu a provést čistý výstup pomocí pcntl_signal.

11
J.D. Fitz.Gerald

Vím, že se jedná o starou otázku, ale pro lidi, kteří hledají, existuje rozšíření PECL napsané v C, které dává PHP vícevláknové schopnosti, nyní je zde https://github.com/ krakjoe/pthreads

8
JasonDavis

použití vláken je možné díky prodloužení PECL pthreads

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

8
pinkal vansia

Dalo by se simulovat závitování. PHP může spouštět procesy na pozadí přes popen (nebo proc_open). Tyto procesy lze komunikovat pomocí stdin a stdout. Tyto procesy mohou samy o sobě být programem php. To je asi tak blízko, jak se dostanete.

5
Pete

Můžete použít exec () ke spuštění skriptu příkazového řádku (například php příkazového řádku), a pokud dáte výstup do souboru, skript nebude čekat na dokončení příkazu.

Nemůžu si úplně vzpomenout na syntaxi php CLI, ale chtěli byste něco jako:

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

Myslím, že docela málo serverů se sdíleným hostingem má ve výchozím nastavení z bezpečnostních důvodů funkci exec () zakázanou, ale možná stojí za to vyzkoušet.

5
Adam Hopkinson

A co pcntl_fork?

podívejte se na naši manuálovou stránku, kde najdete příklady: PHP pcntl_fork

3
Jarrod

V závislosti na tom, co se snažíte udělat, můžete také dosáhnout curl_multi.

3
Sheldmandu

Vím, že je to tak staré, ale mohli byste se podívat na http://phpthreadlib.sourceforge.net/

Podporuje obousměrnou komunikaci mezi vlákny a má také vestavěné ochrany pro zabití podřízených vláken (předcházení sirotkům).

3
Unsigned

pcntl_fork nebude fungovat v prostředí webového serveru, pokud je zapnuto bezpečný režim. V tomto případě bude fungovat pouze ve verzi CLI PHP.

2
Stilero

Máte na výběr:

  1. multi_curl
  2. Jeden může použít systémový příkaz pro totéž
  3. Ideální scénář je vytvořit podprocesovou funkci v jazyce C a kompilovat/konfigurovat v PHP. Tato funkce bude nyní funkcí PHP.
2
Manoj Donga

Třída vlákna je k dispozici, protože PECL pthreads ≥ 2.0.0.

2

V době psaní mého aktuálního komentáře nevím o vláknech PHP. Přišel jsem hledat odpověď zde sám, ale jedním řešením je, že program PHP, který přijímá žádost od webového serveru, deleguje celou formulaci odpovědi na konzolovou aplikaci, která ukládá její výstup, odpověď na požadavek, do binárního souboru a program PHP, který spustil aplikaci konzoly, vrátí tento binární soubor byte-by-byte jako odpověď na přijatý požadavek. Konzolovou aplikaci lze psát v libovolném programovacím jazyce, který běží na serveru, včetně těch, které mají správnou podprocesovou podporu, včetně programů C++, které používají OpenMP.

Jedním nespolehlivým, špinavým trikem je použití PHP pro spuštění aplikace konzoly, „uname“,

uname -a

a vytiskněte výstup tohoto příkazu konzoly do výstupu HTML a zjistěte přesnou verzi serverového softwaru. Poté nainstalujte přesně stejnou verzi softwaru do instance VirtualBox, zkompilujte/sestavte cokoli zcela samostatného, ​​nejlépe statického, binárního souboru, který chce, a poté je nahrajte na server. Od této chvíle může aplikace PHP používat tyto binární soubory v roli aplikace konzoly, která má správné vícevláknové zpracování. Je to špinavé, nespolehlivé řešení situace, kdy správce serveru nenainstaloval na server všechny potřebné implementace programovacího jazyka. Je třeba si dát pozor, aby aplikace PHP při každém požadavku přijala aplikaci konzole, která ukončí/ukončí/get_killed.

Pokud jde o to, co si správci hostingových služeb myslí o takových vzorech využití serveru, myslím, že se to scvrkává na kulturu. V severní Evropě MUSÍ POSKYTOVAT poskytovatel služeb, co bylo reklamováno, a pokud bylo povoleno provádění příkazů konzoly a bylo povoleno nahrávání souborů bez malware a poskytovatel služeb má právo zabít jakýkoli proces serveru po několika minutách nebo dokonce po 30 sekundách , pak administrátoři hostitelských služeb postrádají argumenty pro vytvoření řádné stížnosti. Ve Spojených státech a západní Evropě je situace/kultura velmi odlišná a já věřím, že existuje velká šance, že v USA a/nebo západní Evropě poskytovatel hostingových služeb odmítne sloužit klientům hostingových služeb, kteří používají výše popsaný trik. To je jen můj odhad, vzhledem k mé osobní zkušenosti s hostingovými službami v USA a vzhledem k tomu, co jsem od ostatních slyšel o západoevropských hostingových službách. Když píšu svůj aktuální komentář (2018_09_01), nevím nic o kulturních normách jihoevropských poskytovatelů hostitelských služeb, jihoevropských správců sítí.

0
Martin Vahi