Làm thế nào một người có thể sử dụng đa luồng trong các ứng dụng PHP


414

Có một cách thực tế để thực hiện một mô hình đa luồng trong PHP dù thực sự hay chỉ mô phỏng nó. Đôi khi, có ý kiến ​​cho rằng bạn có thể buộc hệ điều hành tải một phiên bản khác của tệp thực thi PHP và xử lý các quy trình đồng thời khác.

Vấn đề với điều này là khi mã PHP hoàn thành việc thực thi cá thể PHP vẫn còn trong bộ nhớ vì không có cách nào để giết nó từ bên trong PHP. Vì vậy, nếu bạn đang mô phỏng một số chủ đề, bạn có thể tưởng tượng những gì sẽ xảy ra. Vì vậy, tôi vẫn đang tìm kiếm một cách đa luồng có thể được thực hiện hoặc mô phỏng hiệu quả từ bên trong PHP. Có ý kiến ​​gì không?


1
Xem câu hỏi và câu trả lời của tôi tại đây: stackoverflow.com/questions/2101640/ từ
powtac


Cách sử dụng tiện ích mở rộng pthreads: phplobby.com/php-multi-thread-on-windows-pthreads-configuration
Emrah Mehmedov

Có thể quan tâm: pthreads.org
GibboK

Bây giờ vào năm 2020, dường như "song song" php.net/manual/en/intro.abul.php là những gì chúng ta muốn thay vì "pthreads": stackoverflow.com/a/56451969/470749
Ryan

Câu trả lời:


431

Đa luồng có thể có trong php

Có, bạn có thể thực hiện đa luồng trong PHP với pthreads

Từ tài liệu PHP :

pthreads là một API hướng đối tượng, cung cấp tất cả các công cụ cần thiết cho đa luồng trong PHP. Các ứng dụng PHP có thể tạo, đọc, viết, thực thi và đồng bộ hóa với Chủ đề, Công nhân và các đối tượng Threaded.

Cảnh báo : Không thể sử dụng tiện ích mở rộng pthreads trong môi trường máy chủ web. Do đó, luồng trong PHP chỉ nên duy trì cho các ứng dụng dựa trên CLI.

Kiểm tra đơn giản

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

?>

Chạy đầu tiên

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

Lần chạy thứ hai

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

Ví dụ thế giới thực

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, tôi không thể định cấu hình và cài đặt pthread trên máy chủ Xampp. Bạn có thể giúp tôi với đó?
Irfan

4
Tải xuống windows nhị phân tại đây windows.php.net/doads/pecl/release/pthreads/0.0.45
Baba

17
Thật tuyệt, tôi đã không chạm vào PHP trong nhiều năm và bây giờ nó có khả năng đa luồng!
dương

1
Đẹp và đơn giản! Chỉ cần FYI, tôi đang triển khai một ứng dụng trên máy chủ Azure Cloud Win và nếu chỉ chọn cấu hình 1 lõi cơ bản, đa luồng sẽ không khả dụng trừ khi có thêm nhiều lõi.
Milan

3
Xin lưu ý: Joe Watkins, tác giả của tiện ích mở rộng pthreads đã ngừng phát triển theo hướng mở rộng song song mới: github.com/krakjoe/pthreads/issues/929
Anton Belonovich

42

Tại sao bạn không sử dụng 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
Tôi đang sử dụng giải pháp trên và hoạt động tốt, tôi nghĩ rằng đó là cách dễ nhất để thực hiện quy trình song song bằng cách sử dụng php.
GodFather

7
như @ e-info128 đã nói, việc triển khai này tạo ra quy trình, có nghĩa là nó đang chạy trên một quy trình khác và không chia sẻ tài nguyên quy trình. Điều đó đang được nói, nếu công việc trong tay không cần chia sẻ tài nguyên, thì công việc này vẫn sẽ hoạt động và nó sẽ chạy song song.
Raffi

1
Làm thế nào bạn sẽ chuyển các biến để bật mà không sử dụng biến phiên?
atwellpub

@atwellpub Không có cách nào, đây là các quy trình riêng biệt chia sẻ không có tài nguyên. Ngay cả các phiên sẽ là cơ chế IPC khó xử
Cholthi Paul Ttiopic

1
Để truyền dữ liệu cho họ, bạn cũng có thể sử dụng đối số và máy chủ Redis.
Amir cho

21

Việc phân luồng không có sẵn trong kho PHP, nhưng có thể lập trình đồng thời bằng cách sử dụng các yêu cầu HTTP như các cuộc gọi không đồng bộ.

Với cài đặt thời gian chờ của curl được đặt thành 1 và sử dụng cùng session_id cho các quy trình bạn muốn được liên kết với nhau, bạn có thể giao tiếp với các biến phiên như trong ví dụ của tôi dưới đây. Với phương pháp này, bạn thậm chí có thể đóng trình duyệt của mình và quy trình đồng thời vẫn tồn tại trên máy chủ.

Đừng quên xác minh ID phiên chính xác như thế này:

http: //localhost/test/verifysession.php? sessionid = [ id chính xác]

start process.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);

close process.php

if ($_REQUEST["sessionid"])
    session_id($_REQUEST["sessionid"]);

session_start();
$_SESSION["closesession"] = true;
var_dump($_SESSION);

4
Lần trước tôi đã kiểm tra (một vài năm trước) php đã không cho phép truy cập lưu trữ phiên dựa trên tệp bằng hai quy trình cùng một lúc. Nó khóa tập tin và quá trình thứ hai phải ngồi đó chờ tập lệnh đầu tiên dừng lại. Tôi đang nói về môi trường máy chủ web, không phải CLI.
Alexei Tenitski

5
set_time_limit(0);yike! Không bao giờ, bao giờ làm điều này.
Kafoso

@Kafoso Kafoso tại sao không? Tôi đồng ý cho PHP là một bộ xử lý tập lệnh web, nhưng tại sao không có trong CLI? Nếu có sự cố xảy ra, CLI có thể bị giết bằng Ctrl + C ...
sijanec

14

Trong khi bạn không thể xử lý, bạn có một số mức độ kiểm soát quy trình trong php. Hai bộ chức năng hữu ích ở đây là:

Các chức năng kiểm soát quy trình http://www.php.net/manual/en/ref.pcntl.php

Các hàm POSIX http://www.php.net/manual/en/ref.poseix.php

Bạn có thể kết thúc quá trình của mình với pcntl_fork - trả lại PID của con. Sau đó, bạn có thể sử dụng posix_kill để giải quyết vấn đề đó.

Điều đó nói rằng, nếu bạn giết một quá trình cha mẹ, một tín hiệu sẽ được gửi đến tiến trình con bảo nó chết. Nếu bản thân php không nhận ra điều này, bạn có thể đăng ký một chức năng để quản lý nó và thực hiện một lối thoát sạch bằng pcntl_signal.


1
Câu trả lời đó bây giờ rất lỗi thời (điều này rất công bằng khi biết rằng nó 11 tuổi). Nhìn vào pthreads dưới đây.
Maciej Paprocki

@MaciejPaprocki pThread hiện đã ngừng sử dụng fromphp 7.4 thay vào đó sử dụng song song
Airy


10

Tôi biết đây là một câu hỏi cũ nhưng đối với những người tìm kiếm, có một phần mở rộng PECL được viết bằng C cung cấp khả năng đa luồng cho PHP bây giờ, nó nằm ở đây https://github.com/krakjoe/pthreads


pThread hiện đã bị ngừng từ php 7.4, thay vào đó hãy sử dụng song song
Airy

5

Bạn có thể sử dụng exec () để chạy tập lệnh dòng lệnh (chẳng hạn như dòng lệnh php) và nếu bạn chuyển đầu ra thành một tệp thì tập lệnh của bạn sẽ không đợi lệnh kết thúc.

Tôi không thể nhớ cú pháp php CLI, nhưng bạn muốn một cái gì đó như:

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

Tôi nghĩ rằng khá nhiều máy chủ lưu trữ chia sẻ đã bị exec () tắt theo mặc định vì lý do bảo mật, nhưng có thể đáng để thử.


4

Bạn có thể mô phỏng luồng. PHP có thể chạy các quy trình nền thông qua popen (hoặc Proc_open). Những quá trình này có thể được giao tiếp thông qua stdin và stdout. Tất nhiên các quá trình đó có thể tự là một chương trình php. Đó có thể là gần như bạn sẽ nhận được.


3

Tùy thuộc vào những gì bạn đang cố gắng làm, bạn cũng có thể sử dụng curl_multi để đạt được nó.


3

Tôi biết điều này đã cũ, nhưng bạn có thể xem http://phpthreadlib.sourceforge.net/

Nó hỗ trợ giao tiếp giữa các luồng hai chiều và cũng có các biện pháp bảo vệ tích hợp để tiêu diệt các luồng con (ngăn trẻ mồ côi).


3

Bạn có thể có tùy chọn:

  1. đa_curl
  2. Người ta có thể sử dụng lệnh hệ thống cho cùng
  3. Kịch bản lý tưởng là, tạo một hàm luồng trong ngôn ngữ C và biên dịch / cấu hình trong PHP. Bây giờ chức năng đó sẽ là chức năng của PHP.

3

Lớp Thread có sẵn vì pthreads PECL ≥ 2.0.0.


1
Tôi có thể chạy luồng bằng HTTP không? đơn giản: yourname.com/thread.php?
Tên tôi

pThread hiện đã bị ngừng từ php 7.4, thay vào đó hãy sử dụng song song
Airy

3

Làm thế nào về pcntl_fork?

kiểm tra trang hướng dẫn của chúng tôi để biết ví dụ: 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_forksẽ không hoạt động trong môi trường máy chủ web nếu nó được bật chế độ an toàn . Trong trường hợp này, nó sẽ chỉ hoạt động trong phiên bản CLI của PHP.


1

Nếu bạn đang sử dụng máy chủ Linux, bạn có thể sử dụng

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

Nếu bạn cần vượt qua một số đối số

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

Trong script.php

$args = $argv[1];

Hoặc sử dụng Symfony https://symfony.com/doc/cản/components/ Process.html

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

-1

Khi viết bình luận hiện tại của tôi, tôi không biết về các luồng PHP. Tôi đã tự mình tìm kiếm câu trả lời, nhưng một cách giải quyết là chương trình PHP nhận được yêu cầu từ máy chủ web ủy thác toàn bộ công thức trả lời cho một ứng dụng bàn điều khiển lưu trữ đầu ra của nó, câu trả lời cho yêu cầu, cho tệp nhị phân và chương trình PHP đã khởi chạy ứng dụng giao diện điều khiển trả về tệp nhị phân từng byte đó làm câu trả lời cho yêu cầu nhận được. Ứng dụng bàn điều khiển có thể được viết bằng bất kỳ ngôn ngữ lập trình nào chạy trên máy chủ, bao gồm cả những ngôn ngữ có hỗ trợ luồng phù hợp, bao gồm các chương trình C ++ sử dụng OpenMP.

Một mẹo không đáng tin cậy, bẩn thỉu là sử dụng PHP để thực thi một ứng dụng giao diện điều khiển, "uname",

uname -a

và in đầu ra của lệnh console đó sang đầu ra HTML để tìm ra phiên bản chính xác của phần mềm máy chủ. Sau đó cài đặt cùng một phiên bản phần mềm cho phiên bản VirtualBox, biên dịch / lắp ráp bất cứ thứ gì hoàn toàn khép kín, tốt nhất là tĩnh, nhị phân mà người ta muốn và sau đó tải chúng lên máy chủ. Từ thời điểm đó trở đi, ứng dụng PHP có thể sử dụng các nhị phân đó trong vai trò của ứng dụng giao diện điều khiển có đa luồng thích hợp. Đó là một cách giải quyết bẩn thỉu, không đáng tin cậy cho một tình huống, khi quản trị viên máy chủ chưa cài đặt tất cả các cài đặt ngôn ngữ lập trình cần thiết cho máy chủ. Điều cần chú ý là ở mọi yêu cầu mà ứng dụng PHP nhận (các) ứng dụng giao diện điều khiển chấm dứt / exit / get_kills.

Đối với những gì các quản trị viên dịch vụ lưu trữ nghĩ về các kiểu sử dụng máy chủ như vậy, tôi đoán nó sẽ sôi sục với văn hóa. Ở Bắc Âu, nhà cung cấp dịch vụ ĐÃ GIAO HÀNG TUYỆT VỜI LÀ GÌ QUẢNG CÁO và nếu việc thực thi lệnh console được cho phép và tải lên các tệp không phải phần mềm độc hại được cho phép và nhà cung cấp dịch vụ có quyền giết bất kỳ quy trình máy chủ nào sau vài phút hoặc thậm chí sau 30 giây , sau đó các quản trị viên dịch vụ lưu trữ thiếu bất kỳ đối số nào để hình thành khiếu nại thích hợp. Ở Hoa Kỳ và Tây Âu, tình hình / văn hóa rất khác nhau và tôi tin rằng rất có thể ở Mỹ và / hoặc Tây Âu, nhà cung cấp dịch vụ lưu trữ sẽ từ chối phục vụ khách hàng sử dụng dịch vụ lưu trữ sử dụng thủ thuật được mô tả ở trên. Đó chỉ là dự đoán của tôi, dựa trên kinh nghiệm cá nhân của tôi với Hoa Kỳ dịch vụ lưu trữ và đưa ra những gì tôi đã nghe từ những người khác về dịch vụ lưu trữ Tây Âu. Khi viết bình luận hiện tại của tôi (2018_09_01) tôi không biết gì về các chuẩn mực văn hóa của các nhà cung cấp dịch vụ lưu trữ Nam-Âu, quản trị viên mạng Nam-Âu.


-3

Có thể tôi đã bỏ lỡ điều gì đó nhưng exec không hoạt động không đồng bộ với tôi trong môi trường windows tôi đã sử dụng sau trong windows và nó hoạt động như bùa mê;)

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

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

1
Để hack đa luồng trong PHP, bạn nên mở nhiều câu lệnh popen () (PHP sẽ không đợi nó hoàn thành). Sau đó, sau nửa tá mở, bạn gọi pclose () trên những cái đó (PHP sẽ đợi trên pclose () để hoàn thành). Trong mã của bạn, bạn đóng từng luồng ngay sau khi mở nó để mã của bạn không hoạt động như đa luồng.
Kmeixner

-5

Đa luồng có nghĩa là thực hiện đồng thời nhiều tác vụ hoặc quy trình, chúng ta có thể đạt được điều này trong php bằng cách sử dụng mã sau, mặc dù không có cách trực tiếp nào để đạt được đa luồng trong php nhưng chúng ta có thể đạt được kết quả gần như tương tự bằng cách làm theo.

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 .

}

Kiểm tra_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() ");

}

Điều này sẽ thực thi test_1.php hai lần cùng một lúc và cả hai quá trình sẽ chạy trong nền đồng thời, vì vậy bằng cách này bạn có thể đạt được đa luồng trong php.

Anh chàng này đã làm rất tốt công việc Đa luồng trong php


Ngoài ra, điều này không có gì để làm với MultiThreading. Đây là xử lý song song. Những điều hoàn toàn khác nhau.
Nhân kỹ thuật số

Theo tôi là một cách giải quyết, một vụ hack khẩn cấp, ý tưởng đằng sau giải pháp được đưa ra là rất phù hợp, nhưng tôi đoán những người khác nhau có thể có những cuộc chiến nảy lửa về những gì cấu thành "đa luồng thực sự", bởi vì có sự phân biệt giữa đồng thời và dựa trên phần cứng xử lý song song, như được mô tả tại: youtube.com/watch?v=cN_DpYBzKso
Martin Vahi
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.