PHP uygulamalarında çoklu iş parçacığı nasıl kullanılır


414

PHP'de çok iş parçacıklı bir modeli uygulamak için gerçekçi bir yol var mı, yoksa sadece simüle. Bir süre önce, işletim sistemini PHP çalıştırılabilirinin başka bir örneğini yüklemeye ve diğer eşzamanlı işlemleri işlemeye zorlayabileceğiniz önerildi.

Bu sorun, PHP kodu PHP örneğini yürütmeyi bitirdiğinde PHP içinde öldürmek için bir yolu olmadığı için bellekte kalır olmasıdır. Eğer birkaç iş parçacığını simüle ediyorsanız ne olacağını hayal edebilirsiniz. Bu yüzden hala çok iş parçacığının PHP içinden etkili bir şekilde yapılabileceği veya simüle edilebileceği bir yol arıyorum. Herhangi bir fikir?


1
Sorum ve cevaplarımı burada görebilirsiniz: stackoverflow.com/questions/2101640/…
powtac



Belki de ilgi çekici: pthreads.org
GibboK

Şimdi 2020'de, "paralel" gibi görünüyor php.net/manual/tr/intro.parallel.php "pthreads" yerine istediğimiz şey: stackoverflow.com/a/56451969/470749
Ryan

Yanıtlar:


431

Php çoklu iş parçacığı mümkündür

Evet pthreads ile PHP'de çoklu iş parçacığı yapabilirsiniz

Gönderen PHP belgelerine :

pthreads, PHP'de çoklu iş parçacığı oluşturmak için gereken tüm araçları sağlayan, nesne yönelimli bir API'dir. PHP uygulamaları Konular, İşçiler ve Dişli nesneler oluşturabilir, okuyabilir, yazabilir, yürütebilir ve senkronize edebilir.

Uyarı : pthreads uzantısı bir web sunucusu ortamında kullanılamaz. Bu nedenle PHP'de iş parçacığı oluşturma işlemi yalnızca CLI tabanlı uygulamalarda kalmalıdır.

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

?>

İlk Koşu

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

İkinci Koşu

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

Gerçek Dünya Örneği

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

3
@Baba, Xampp sunucusuna pthreads yapılandıramıyor ve yükleyemiyorum. Bana bununla yardım edebilir misin?
Irfan

4
Windows ikili dosyasını buradan indirin windows.php.net/downloads/pecl/releases/pthreads/0.0.45
Baba

17
Bu güzel, yıllardır PHP dokunmadım ve şimdi multithreading yetenekleri var!
Mart'ta kruvazör

1
Güzel ve basit! Sadece FYI, Azure Cloud Win sunucusunda bir uygulama dağıtıyorum ve yalnızca temel 1 çekirdek yapılandırması seçilirse, daha fazla çekirdek eklenmedikçe çoklu iş parçacığı kullanılamaz.
Milano

3
Lütfen dikkat: pthreads uzantının yazarı Joe Watkins, yeni paralel uzantı lehine gelişimi durdurdu: github.com/krakjoe/pthreads/issues/929
Anton Belonovich

42

neden kullanmak yok 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]);
    }
}

4
Yukarıdaki çözümü kullanıyorum ve iyi çalışıyor, ben php kullanarak paralel işlem yapmanın en kolay yolu olduğunu düşünüyorum.
GodFather

7
@ e-info128 gibi, bu uygulama süreci çatallar, yani farklı bir süreç üzerinde çalışıyor demektir ve süreç kaynaklarını paylaşmaz. Bununla birlikte, eldeki işin kaynak paylaşması gerekmiyorsa, bu hala işe yarayacak ve paralel olarak çalışacaktır.
Raffi

1
Oturum değişkenlerini kullanmadan değişkenleri popen'e nasıl iletirsiniz?
atwellpub

@atwellpub Hiçbir şekilde, bunlar hiçbir kaynağı paylaşmayan ayrı süreçlerdir. Hatta oturumlar bile IPC mekanizması garip olacak
Cholthi Paul Ttiopic

1
Onlara veri aktarmak için argümanları ve Redis sunucusunu da kullanabilirsiniz.
Amir Fo

21

İş parçacığı PHP'de iş parçacığı mevcut değildir, ancak eşzamanlı programlama HTTP isteklerini eşzamansız çağrılar olarak kullanmak mümkündür.

Kıvrımın zaman aşımı ayarı 1 olarak ayarlandığında ve birbiriyle ilişkilendirmek istediğiniz işlemler için aynı session_id değerini kullanarak, aşağıdaki örnekte olduğu gibi oturum değişkenleriyle iletişim kurabilirsiniz. Bu yöntemle tarayıcınızı bile kapatabilirsiniz ve eşzamanlı işlem hala sunucuda mevcuttur.

Bunun gibi doğru oturum kimliğini doğrulamayı unutmayın:

http: //localhost/test/verifysession.php? sessionid = [ doğru kimlik]

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
Son kontrolüm (birkaç yıl önce) php, aynı anda iki işlemle dosya tabanlı oturum depolamasına erişime izin vermedi. Dosyayı kilitler ve ikinci işlem ilk komut dosyasının durmasını bekleyen orada oturmak zorundadır. CLI değil web sunucusu ortamından bahsediyorum.
Alexei Tenitski

5
set_time_limit(0);yikes! Asla, asla yapma.
Kafoso

@Kafoso Kafoso neden olmasın? Ben bir web script işlemci olarak PHP için katılıyorum, ama neden CLI değil? Bir şeyler ters giderse, CLI Ctrl + C ile öldürülebilir ...
sijanec

14

Eğer iş parçacığı olamazken, php süreç kontrolü bir derece var. Burada yararlı olan iki işlev kümesi şunlardır:

Süreç kontrol fonksiyonları http://www.php.net/manual/en/ref.pcntl.php

POSIX işlevleri http://www.php.net/manual/en/ref.posix.php

İşleminizi pcntl_fork ile çatabilirsiniz - çocuğun PID'sini döndürür. Ardından bu PID'yi atmak için posix_kill komutunu kullanabilirsiniz.

Bununla birlikte, bir ebeveyn sürecini öldürürseniz, çocuk sürecine ölmesini söyleyen bir sinyal gönderilmelidir. Php kendisi bunu tanımıyorsa, onu yönetmek ve pcntl_signal kullanarak temiz bir çıkış yapmak için bir işlev kaydedebilirsiniz.


1
Bu cevap şimdi çok eski (11 yaşında olduğunu bilmek çok adil). Aşağıdaki pthreads'ye bakın.
Maciej Paprocki

@MaciejPaprocki pThread artık durduruldu fromphp 7.4 yerine paralel kullanın
Airy


10

Bu eski bir soru olduğunu biliyorum ama arama insanlar için, şimdi PHP çoklu iş parçacığı yeteneği veren C yazılı bir PECL uzantısı var, burada bulunur https://github.com/krakjoe/pthreads


pThread artık php 7.4 ile üretilmiyor, bunun yerine paralel kullan
Airy

5

Bir komut satırı komut dosyasını (komut satırı php gibi) çalıştırmak için exec () kullanabilirsiniz ve çıktıyı bir dosyaya bağlarsanız, komut dosyanız komutun bitmesini beklemez.

Php CLI sözdizimini oldukça hatırlayamıyorum, ancak şöyle bir şey istersiniz:

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

Bence birkaç paylaşılan barındırma sunucusu, güvenlik nedeniyle varsayılan olarak exec () devre dışıdır, ancak denemeye değer olabilir.


4

İpliği taklit edebilirsiniz. PHP arka plan işlemlerini popen (veya proc_open) yoluyla çalıştırabilir. Bu işlemler stdin ve stdout aracılığıyla iletilebilir. Tabii bu süreçlerin kendileri bir php programı olabilir. Muhtemelen alacağınız kadar yakın.


3

Ne yapmaya çalıştığınıza bağlı olarak bunu başarmak için curl_multi kullanabilirsiniz.



3

Şunlardan birini seçebilirsiniz:

  1. multi_curl
  2. Aynı sistem komutunu kullanabilirsiniz
  3. İdeal senaryo, C dilinde bir iş parçacığı işlevi oluşturmak ve PHP'de derlemek / yapılandırmaktır. Şimdi bu fonksiyon PHP'nin fonksiyonu olacak.


3

Pcntl_fork nasıl?

örnekler için kılavuz sayfamıza bakın: 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
    }

?>

2

pcntl_forkgüvenli mod açıksa web sunucusu ortamında çalışmaz . Bu durumda, yalnızca PHP'nin CLI sürümünde çalışır.


1

Bir Linux sunucusu kullanıyorsanız,

exec("nohup $php_path path/script.php > /dev/null 2>/dev/null &")

Eğer bazı argümanlar geçmek gerekiyorsa

exec("nohup $php_path path/script.php $args > /dev/null 2>/dev/null &")

Script.php içinde

$args = $argv[1];

Veya Symfony https://symfony.com/doc/current/components/process.html adresini kullanın

$process = Process::fromShellCommandline("php ".base_path('script.php'));
$process->setTimeout(0);     
$process->disableOutput();     
$process->start();

-1

Benim mevcut yorum yazma itibariyle, PHP konu hakkında bilmiyorum. Cevabı burada aramaya geldim, ancak bir çözüm, web sunucusundan istek alan PHP programının tüm cevap formülasyonunu çıktısını, isteğin cevabını, bir ikili dosyaya depolayan bir konsol uygulamasına devretmesidir. ve konsol uygulamasını başlatan PHP programı, ikili dosya bayt-byte değerini alınan isteğin yanıtı olarak döndürür. Konsol uygulaması, OpenMP kullanan C ++ programları da dahil olmak üzere uygun iş parçacığı desteğine sahip olanlar da dahil olmak üzere sunucuda çalışan herhangi bir programlama dilinde yazılabilir.

Güvenilmez, kirli bir numara, konsol uygulamasını "uname",

uname -a

ve sunucu yazılımının tam sürümünü bulmak için bu konsol komutunun çıktısını HTML çıktısına yazdırın. Ardından, yazılımın tam olarak aynı sürümünü bir VirtualBox örneğine yükleyin, tam olarak kendine yeten, tercihen statik olan herhangi bir dosyayı derleyin / birleştirin ve sonra bunları sunucuya yükleyin. Bu noktadan itibaren PHP uygulaması uygun ikili iş parçacığına sahip konsol uygulaması rolünde bu ikili dosyaları kullanabilir. Sunucu yöneticisi gerekli tüm programlama dili uygulamalarını sunucuya yüklemediğinde, bu durum kirli, güvenilir olmayan bir çözümdür. Dikkat edilmesi gereken şey, PHP uygulamasının konsol uygulamalarını aldığı her istekte sonlandırılır / exit / get_killed.

Hosting hizmeti yöneticilerinin bu tür sunucu kullanım kalıpları hakkında ne düşündüklerine gelince, sanırım kültüre kaynar. Kuzey Avrupa'da servis sağlayıcı REKLAM VERİLENİ SAĞLAMALIDIR ve konsol komutlarının yürütülmesine izin verilmişse ve kötü amaçlı yazılım olmayan dosyaların yüklenmesine izin verilmişse ve servis sağlayıcısı herhangi bir sunucu işlemini birkaç dakika sonra veya 30 saniye sonra öldürme hakkına sahiptir. , daha sonra barındırma hizmeti yöneticileri uygun bir şikayet oluşturmak için herhangi bir argüman eksik. Amerika Birleşik Devletleri ve Batı Avrupa'da durum / kültür çok farklıdır ve ABD ve / veya Batı Avrupa'da barındırma hizmeti sağlayıcısının yukarıda açıklanan numarayı kullanan barındırma hizmeti müşterilerine hizmet vermeyi reddetme şansı olduğuna inanıyorum. ABD ile kişisel deneyimim göz önüne alındığında, bu sadece benim tahminim barındırma hizmetleri ve Batı Avrupa barındırma hizmetleri hakkında başkalarından ne duydum verildi. Mevcut yorumumun yazılması itibariyle (2018_09_01) Güney Avrupa barındırma hizmeti sağlayıcıları olan Güney Avrupa ağ yöneticilerinin kültürel normları hakkında hiçbir şey bilmiyorum.


-3

Belki bir şey özledim ama exec ben pencerelerde aşağıdaki kullanılan windows ortamında benim için asenkron olarak işe yaramadı ve çekicilik gibi çalıştı;)

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

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

1
PHP'de çoklu iş parçacığını kesmek için birden çok popen () ifadesi açmalısınız (PHP tamamlanmasını beklemez). Sonra yarım düzine kadar açık sonra bunlara pclose () çağırmak (PHP pclose () tamamlamak için bekleyecek). Kodunuzda, her iş parçacığını açtıktan hemen sonra kapatırsınız, böylece kodunuz çok iş parçacıklı gibi davranmaz.
Kmeixner

-5

Multithreading, birden fazla görevi veya işlemi aynı anda gerçekleştirmek anlamına gelir, php'de multithreading elde etmenin doğrudan bir yolu olmamasına rağmen, aşağıdaki kodu kullanarak php'de bunu başarabiliriz, ancak aşağıdaki yolla neredeyse aynı sonuçları elde edebiliriz.

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

}

Bu, test_1.php'yi aynı anda iki kez yürütür ve her iki işlem de aynı anda arka planda çalışır, böylece php'de çoklu iş parçacığı elde edebilirsiniz.

Bu adam php Multithreading gerçekten iyi iş bitti


Ayrıca, bunun MultiThreading ile hiçbir ilgisi yoktur. Bu paralel işlemedir. Tamamen farklı şeyler.
Dijital İnsan

Bence bir geçici çözüm, acil bir hack, sunulan çözümün arkasındaki fikir çok uygun, ama sanırım farklı insanlar "gerçek çoklu iş parçacığını" neyin oluşturduğu hakkında alev savaşları yaşayabilirler, çünkü eşzamanlılık ve donanım tabanlı bir ayrım var paralel işleme, burada açıklandığı gibi: youtube.com/watch?v=cN_DpYBzKso
Martin Vahi
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.