วิธีหนึ่งสามารถใช้หลายเธรดในแอปพลิเคชัน PHP


414

มีวิธีการใช้โมเดลแบบมัลติเธรดใน PHP อย่างแท้จริงไม่ว่าจะเป็นจริงหรือเพียงแค่จำลองมัน บางครั้งก็มีข้อเสนอแนะว่าคุณสามารถบังคับให้ระบบปฏิบัติการโหลดอินสแตนซ์อื่นของไฟล์ปฏิบัติการ PHP และจัดการกระบวนการอื่น ๆ พร้อมกัน

ปัญหานี้คือเมื่อรหัส PHP เสร็จสิ้นการดำเนินการเช่น PHP ยังคงอยู่ในหน่วยความจำเพราะไม่มีวิธีที่จะฆ่ามันจากภายใน PHP ดังนั้นหากคุณจำลองหลายเธรดคุณสามารถจินตนาการได้ว่าจะเกิดอะไรขึ้น ดังนั้นฉันยังคงมองหาวิธีที่สามารถทำได้หลายแบบหรือหลายเธรดจากภายใน PHP ได้อย่างมีประสิทธิภาพ ความคิดใด ๆ


1
ดูคำถามและคำตอบของฉันที่นี่: stackoverflow.com/questions/2101640/…
powtac


วิธีใช้ส่วนขยาย pthreads: phplobby.com/php-multi-thread-on-windows-pthreads-configuration
Emrah Mehmedov

อาจจะเป็นที่น่าสนใจ: pthreads.org
GibboK

ตอนนี้ในปี 2020 ดูเหมือนว่า "ขนาน" php.net/manual/en/intro.parallel.phpคือสิ่งที่เราต้องการแทนที่จะเป็น "pthreads": stackoverflow.com/a/56451969/470749
Ryan

คำตอบ:


431

หลายเธรดเป็นไปได้ใน php

ใช่คุณสามารถทำหลายเธรดใน PHP ด้วยpthreads

จากเอกสาร PHP :

pthreads เป็น object-orientated 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);
}

3
@ บาบาฉันไม่สามารถกำหนดค่าและติดตั้ง pthreads บนเซิร์ฟเวอร์ Xampp คุณช่วยฉันได้ไหม
Irfan

4
ดาวน์โหลด windows binary ได้ที่นี่windows.php.net/downloads/pecl/releases/pthreads/0.0.45
Baba

17
เยี่ยมมากฉันไม่ได้แตะ PHP มาหลายปีแล้วและตอนนี้ก็มีความสามารถในการทำงานแบบมัลติเธรด!
เดินเรือ

1
ดีและเรียบง่าย! เพียง FYI ฉันกำลังปรับใช้แอพบนเซิร์ฟเวอร์ Azure Cloud Win และหากเลือกเฉพาะการกำหนดค่าพื้นฐาน 1 คอร์มัลติเธรดจะไม่สามารถใช้งานได้เว้นแต่จะเพิ่มคอร์เพิ่มเติม
มิลาน

3
โปรดระวัง: Joe Watkins ผู้เขียนส่วนขยาย pthreads หยุดการพัฒนาเพื่อสนับสนุนการขยายขนานใหม่: github.com/krakjoe/pthreads/issues/929
Anton Belonovich

42

ทำไมคุณไม่ใช้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
ฉันใช้วิธีแก้ปัญหาข้างต้นและใช้งานได้ดีฉันคิดว่ามันเป็นวิธีที่ง่ายที่สุดในการทำกระบวนการแบบขนานโดยใช้ php
GodFather

7
เช่น @ e-info128 กล่าวว่าการดำเนินการนี้ใช้กระบวนการซึ่งหมายความว่ามันกำลังทำงานบนกระบวนการที่แตกต่างกันและไม่แชร์ทรัพยากรกระบวนการ ที่ถูกกล่าวว่าถ้างานในมือไม่จำเป็นต้องใช้ทรัพยากรร่วมกันสิ่งนี้จะยังคงใช้ได้และมันจะทำงานแบบขนาน
Raffi

1
คุณจะส่งผ่านตัวแปรไปยัง popen โดยไม่ใช้ตัวแปรเซสชันได้อย่างไร
atwellpub

@atwellpub ไม่มีวิธีเหล่านี้เป็นกระบวนการแยกต่างหากที่ไม่มีทรัพยากรร่วมกัน แม้ช่วงการประชุมจะเป็นกลไก IPC ที่น่าอึดอัดใจ
Cholthi Paul Ttiopic

1
ในการส่งผ่านข้อมูลไปยังพวกเขาคุณสามารถใช้อาร์กิวเมนต์และเซิร์ฟเวอร์ Redis ได้เช่นกัน
Amir Fo

21

เธรดไม่พร้อมใช้งานในสต็อก PHP แต่สามารถเขียนโปรแกรมพร้อมกันได้โดยใช้คำขอ HTTP เป็นการโทรแบบอะซิงโครนัส

ด้วยการตั้งค่าการหมดเวลาของ curl ให้ตั้งค่าเป็น 1 และใช้ session_id เดียวกันสำหรับกระบวนการที่คุณต้องการเชื่อมโยงซึ่งกันและกันคุณสามารถสื่อสารกับตัวแปรเซสชันได้ในตัวอย่างด้านล่าง ด้วยวิธีนี้คุณสามารถปิดเบราว์เซอร์ของคุณและกระบวนการที่เกิดขึ้นพร้อมกันยังคงมีอยู่บนเซิร์ฟเวอร์

อย่าลืมตรวจสอบรหัสเซสชันที่ถูกต้องเช่นนี้

http: //localhost/test/verifysession.php? sessionid = [ 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);

4
ครั้งล่าสุดที่ฉันตรวจสอบ (ไม่กี่ปีที่ผ่านมา) php ไม่อนุญาตให้เข้าถึงที่จัดเก็บข้อมูลตามเซสชันด้วยสองกระบวนการพร้อมกัน มันล็อคไฟล์และกระบวนการที่สองต้องนั่งรอที่สคริปต์แรกจะหยุด ฉันกำลังพูดถึงสภาพแวดล้อมเว็บเซิร์ฟเวอร์ไม่ใช่ CLI
Alexei Tenitski

5
set_time_limit(0);อ๊ะ! ไม่เคยทำเช่นนี้
Kafoso

@Kafoso Kafoso ทำไมล่ะ? ฉันเห็นด้วยกับ PHP ในฐานะตัวประมวลผลสคริปต์เว็บ แต่ทำไมไม่ใช้ CLI หากมีสิ่งผิดปกติ CLI ก็สามารถถูกฆ่าได้ด้วย Ctrl + C ...
sijanec

14

ในขณะที่คุณไม่สามารถเธรดคุณจะมีระดับการควบคุมกระบวนการใน 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


1
คำตอบนั้นล้าสมัยไปแล้ว (ซึ่งยุติธรรมมากเมื่อรู้ว่ามีอายุ 11 ปี) ดู pthreads ด้านล่าง
Maciej Paprocki

@MaciejPaprocki p เธรดถูกยกเลิกจาก php 7.4 แทนที่จะใช้แบบขนาน
Airy


10

ฉันรู้ว่านี่เป็นคำถามเก่า แต่สำหรับคนที่ค้นหามีส่วนขยาย PECL เขียนใน C ที่ให้ความสามารถในการเธรด PHP แบบหลายเธรดอยู่ที่นี่https://github.com/krakjoe/pthreads


pThread ถูกยกเลิกจาก php 7.4 แทนที่จะใช้แบบขนาน
Airy

5

คุณสามารถใช้ exec () เพื่อรันสคริปต์บรรทัดคำสั่ง (เช่น php บรรทัดคำสั่ง) และหากคุณไพพ์เอาต์พุตไปยังไฟล์สคริปต์ของคุณจะไม่รอให้คำสั่งเสร็จสิ้น

ฉันไม่สามารถจำไวยากรณ์ php CLI ได้ค่อนข้างมาก แต่คุณต้องการ:

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

ฉันคิดว่าเซิร์ฟเวอร์โฮสติ้งที่ใช้ร่วมกันค่อนข้างน้อยได้ปิดการใช้งาน exec () ตามค่าเริ่มต้นด้วยเหตุผลด้านความปลอดภัย แต่อาจคุ้มค่ากับการลอง


4

คุณสามารถจำลองเกลียว PHP สามารถเรียกใช้กระบวนการพื้นหลังผ่าน popen (หรือ proc_open) กระบวนการเหล่านั้นสามารถสื่อสารผ่านทาง stdin และ stdout แน่นอนว่ากระบวนการเหล่านั้นสามารถเป็นโปรแกรม php ได้ นั่นอาจใกล้เคียงกับที่คุณจะได้รับ


3

ขึ้นอยู่กับสิ่งที่คุณพยายามทำคุณสามารถใช้ curl_multi เพื่อให้บรรลุ


3

ฉันรู้ว่ามันเก่าไปแล้ว แต่คุณสามารถดูได้ที่http://phpthreadlib.sourceforge.net/

รองรับการสื่อสารระหว่างเธรดสองทิศทางและยังมีการป้องกันในตัวสำหรับฆ่าเธรดเด็ก (ป้องกันเด็กกำพร้า)


3

คุณสามารถมีตัวเลือก:

  1. multi_curl
  2. หนึ่งสามารถใช้คำสั่งระบบสำหรับเดียวกัน
  3. สถานการณ์ในอุดมคติคือสร้างฟังก์ชั่นเกลียวในภาษา C และรวบรวม / กำหนดค่าใน PHP ตอนนี้ฟังก์ชั่นนั้นจะเป็นหน้าที่ของ PHP


3

แล้ว 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
    }

?>

2

pcntl_forkจะไม่ทำงานในสภาพแวดล้อมของเว็บเซิร์ฟเวอร์หากเปิดเซฟโหมดไว้ ในกรณีนี้มันจะทำงานในเวอร์ชัน CLI ของ PHP เท่านั้น


1

หากคุณใช้เซิร์ฟเวอร์ Linux คุณสามารถใช้

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

ถ้าคุณต้องการผ่าน args

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

ใน script.php

$args = $argv[1];

หรือใช้ Symfony https://symfony.com/doc/current/components/process.html

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

-1

จากการเขียนความคิดเห็นปัจจุบันของฉันฉันไม่รู้เกี่ยวกับเธรด PHP ฉันมาเพื่อค้นหาคำตอบที่นี่ด้วยตัวเอง แต่วิธีแก้ปัญหาหนึ่งคือโปรแกรม PHP ที่ได้รับการร้องขอจากเว็บเซิร์ฟเวอร์มอบหมายสูตรคำตอบทั้งหมดให้กับแอปพลิเคชั่นคอนโซลที่เก็บเอาท์พุทคำตอบคำขอไปยังไฟล์ไบนารี และโปรแกรม PHP ที่เปิดตัวแอปพลิเคชั่นคอนโซลจะส่งคืนไฟล์ไบนารี่ไบต์ต่อไบต์เป็นคำตอบของคำขอที่ได้รับ แอ็พพลิเคชันคอนโซลสามารถเขียนในภาษาการเขียนโปรแกรมใด ๆ ที่รันบนเซิร์ฟเวอร์รวมถึงที่มีเธรดที่เหมาะสมรวมถึงโปรแกรม C ++ ที่ใช้ OpenMP

เคล็ดลับที่ไม่น่าเชื่อถือและสกปรกอย่างหนึ่งคือการใช้ PHP สำหรับการเรียกใช้แอปพลิเคชันคอนโซล "uname"

uname -a

และพิมพ์เอาต์พุตของคำสั่งคอนโซลนั้นไปยังเอาต์พุต HTML เพื่อค้นหาเวอร์ชันที่แน่นอนของซอฟต์แวร์เซิร์ฟเวอร์ จากนั้นติดตั้งซอฟต์แวร์รุ่นเดียวกันที่แน่นอนไปยังอินสแตนซ์ VirtualBox รวบรวม / ประกอบสิ่งที่มีอยู่ในตัวเองอย่างสมบูรณ์แบบคงที่โดยเฉพาะอย่างยิ่งไบนารีที่หนึ่งต้องการแล้วอัปโหลดไปยังเซิร์ฟเวอร์ จากจุดนั้นเป็นต้นมาแอปพลิเคชัน PHP สามารถใช้ไบนารีเหล่านั้นในบทบาทของคอนโซลแอปพลิเคชันที่มีเธรดหลายเธรดที่เหมาะสม เป็นสถานการณ์ที่สกปรกไม่น่าเชื่อถือและหลีกเลี่ยงปัญหาเมื่อผู้ดูแลระบบเซิร์ฟเวอร์ไม่ได้ติดตั้งการปรับใช้ภาษาการเขียนโปรแกรมที่จำเป็นทั้งหมดไปยังเซิร์ฟเวอร์ สิ่งที่ต้องระวังคือทุกครั้งที่แอปพลิเคชัน PHP ได้รับแอปพลิเคชันคอนโซลจะยุติ / exit / get_killed

สำหรับสิ่งที่ผู้ดูแลระบบบริการโฮสติ้งคิดเกี่ยวกับรูปแบบการใช้งานเซิร์ฟเวอร์ฉันคิดว่ามันน่าสนใจมาก ในยุโรปเหนือผู้ให้บริการจะทำการจัดส่งสิ่งที่โฆษณาและหากอนุญาตให้ดำเนินการคำสั่งคอนโซลและอัปโหลดไฟล์ที่ไม่ใช่มัลแวร์ได้รับอนุญาตและผู้ให้บริการมีสิทธิ์ฆ่ากระบวนการเซิร์ฟเวอร์หลังจากผ่านไปสองสามนาทีหรือแม้กระทั่งหลังจาก 30 วินาที ดังนั้นผู้ดูแลบริการโฮสต์ไม่มีข้อโต้แย้งใด ๆ ในสหรัฐอเมริกาและยุโรปตะวันตกสถานการณ์ / วัฒนธรรมแตกต่างกันมากและฉันเชื่อว่ามีโอกาสที่ดีที่ในสหรัฐอเมริกาและ / หรือยุโรปตะวันตกผู้ให้บริการโฮสติ้งจะปฏิเสธที่จะให้บริการลูกค้าที่ให้บริการโฮสต์ที่ใช้เคล็ดลับที่อธิบายไว้ข้างต้น นั่นเป็นเพียงการเดาของฉันให้ประสบการณ์ส่วนตัวกับฉัน บริการโฮสติ้งและให้สิ่งที่ฉันได้ยินจากผู้อื่นเกี่ยวกับบริการโฮสติ้งของยุโรปตะวันตก จากการเขียนความคิดเห็นปัจจุบันของฉัน (2018_09_01) ฉันไม่รู้อะไรเกี่ยวกับบรรทัดฐานทางวัฒนธรรมของผู้ให้บริการโฮสติ้งยุโรปใต้ผู้บริหารเครือข่ายยุโรปใต้


-3

ฉันอาจจะพลาดบางอย่าง แต่ผู้บริหารไม่ได้ทำงานแบบอะซิงโครนัสสำหรับฉันในสภาพแวดล้อมของ windows ฉันใช้งานต่อไปนี้ใน Windows และทำงานได้อย่างมีเสน่ห์;)

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

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

1
ในการแฮ็คมัลติเธรดใน PHP คุณควรเปิดข้อความ popen () หลายรายการ (PHP จะไม่รอให้เสร็จสมบูรณ์) จากนั้นหลังจากเปิดครึ่งโหลหรือมากกว่านั้นคุณจะเรียก pclose () ที่ (PHP จะรอ pclose () ให้เสร็จสมบูรณ์) ในรหัสของคุณคุณปิดแต่ละกระทู้ทันทีหลังจากเปิดเพื่อให้รหัสของคุณจะไม่ทำงานเหมือนมัลติเธรด
Kmeixner

-5

Multithreading หมายถึงการปฏิบัติงานหรือกระบวนการหลายอย่างพร้อมกันเราสามารถบรรลุสิ่งนี้ใน php โดยใช้รหัสต่อไปนี้แม้ว่าจะไม่มีวิธีโดยตรงในการบรรลุ multithreading ใน 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 ได้

ผู้ชายคนนี้ทำงานได้ดีมาก Multithreading ใน php


นอกจากนี้ยังไม่มีสิ่งที่ต้องทำกับ MultiThreading นี่คือการประมวลผลแบบขนาน สิ่งที่แตกต่างกันโดยสิ้นเชิง
มนุษย์ดิจิทัล

ในความคิดของฉันในฐานะวิธีแก้ปัญหาการแฮ็คฉุกเฉินแนวคิดเบื้องหลังโซลูชันที่เสนอนั้นเหมาะสมมาก แต่ฉันคิดว่าผู้คนที่แตกต่างกันสามารถมีสงครามเปลวไฟเกี่ยวกับสิ่งที่ถือเป็น "เธรดมัลติเธรดที่แท้จริง" เนื่องจากมีความแตกต่างระหว่าง การประมวลผลแบบขนานตามที่อธิบายไว้ที่: youtube.com/watch?v=cN_DpYBzKso
Martin Vahi
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.