Cara menggunakan create thread in php

02 April 2021 1 min read

Disclaimer
Saya bekerja di AWS, semua opini adalah dari saya pribadi. (I work for AWS, my opinions are my own.)

Cara menggunakan create thread in php
Photo by Jonathan Chng on Unsplash

TeknoCerdas.com – Salam cerdas untuk kita semua. Java sudah dikenal dari dulu adalah bahasa yang mendukung multi-threading. Dengan multi-threading maka sebuah task dapat berlangsung pada waktu bersamaan. PHP adalah bahasa pemrograman yang hanya mendukung single thread. Untuk implementasi multi-threading pada PHP dapat dilakukan dengan bantuan Java Virtual Machine (JVM). Artinya kode PHP akan diubah ke Javabyte code.

Pada tulian ini mengubah kode PHP menjadi Java bytecode dilakukan dengan bantuan JPHP. Sebuah compiler PHP untuk JVM. Secara otomatis dengan ter-compile sebagai Java bytecode maka PHP dapat memanfaatkan fitur JVM salah satunya multi-threading.

Silahkan merujuk pada artikel link dibawah ini untuk langkah-langkah bagaimana menginstal JPHP pada Linux.

Baca Juga
Menjalankan PHP pada Java Virtual Machine (JVM)

Multi-Threading dengan JPHP

Untuk menggunakan thread pada JPHP dapat digunakan pustaka yang tersedia pada namespace php\lang\Thread. Cara penggunaannya mirip dengan yang ada di Java.

Berikut ini adalah contoh kode multi-threading sederhana memanfaatkan pustaka yang disediakan JPHP.

Kita inisialisasi terlebih dulu sebuah project baru.

$ mkdir jphp-thread && cd jphp-thread
$ jppm init

Isikan saja semuanya secara default pada prompt yang tampil. Kemudian Edit file src/index.php dan sesuaikan kodenya seperti berikut.

use php\lang\Thread;

$t1 = new Thread(function() {
    // Simulate a task which took 2 seconds
    Thread::sleep(2000);
    echo "Thread #1 sleep for 2 secs.\n";
});
$t1->start();

$t2 = new Thread(function() {
    // Simulate a task which took half a second
    Thread::sleep(500);
    echo "Thread #2 sleep for 0.5 secs.\n";
});
$t2->start();

echo "Hello World.\n";

Ketika dijalankan output yang dihasilkan akan seperti dibawah.

$ jppm start
Hello World.
Thread #2 sleep for 0.5 secs.
Thread #1 sleep for 2 secs.

Dapat terlihat jika kode dieksekusi secara bersamaan dan tidak secara seri atau berurutan.

Statement echo "Hello World\n" menjadi nomor satu karena prosesnya sangat cepat sehingga CPU akan mengeksekusinya pertama kali. Statement tersebut berada pada main Thread.

Kemudian kita membuat dua Thread baru yatu Thread 1 dan Thread 2. Thread 1 disimulasikan sebuah task yang cukup berat yaitu selesai dalam waktu 2 detik.

Secara bersamaan Thread 2 juga dimulai dan tasknya butuh waktu lebih cepat dari Thread 1 yaitu hanya 0.5 detik sehingga statemen pada Thread 2 yang dieksekusi terlebih dahulu oleh CPU yang menghasilkan output seperti diatas.

Apakah ada cara realistis untuk mengimplementasikan model multi-berulir dalam PHP apakah benar-benar, atau hanya mensimulasikannya. Beberapa waktu lalu disarankan agar Anda dapat memaksa sistem operasi untuk memuat instance PHP lainnya yang dapat dieksekusi dan menangani proses simultan lainnya.

Masalahnya adalah ketika kode PHP selesai mengeksekusi instance PHP tetap ada dalam memori karena tidak ada cara untuk membunuhnya dari dalam PHP. Jadi, jika Anda mensimulasikan beberapa utas, Anda dapat membayangkan apa yang akan terjadi. Jadi saya masih mencari cara multi-threading dapat dilakukan atau disimulasikan secara efektif dari dalam PHP. Ada ide?

Multi-threading dimungkinkan di php

Ya, Anda dapat melakukan multi-threading dalam PHP dengan pthreads

Dari dokumentasi PHP :

pthreads adalah API berorientasi objek yang menyediakan semua alat yang diperlukan untuk multi-threading di PHP. PHP aplikasi dapat membuat, membaca, menulis, mengeksekusi, dan menyinkronkan dengan Thread, Pekerja, dan objek berulir.

Peringatan : Ekstensi pthreads tidak dapat digunakan di lingkungan server web. Oleh karena itu, pengarsipan dalam PHP harus tetap hanya untuk aplikasi berbasis CLI.

Tes Sederhana

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

?>

Lari pertama

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

Jalankan Kedua

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

Contoh Dunia Nyata

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

kenapa kamu tidak menggunakan 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]);
    }
}

Threading tidak tersedia dalam stok PHP, tetapi pemrograman bersamaan dimungkinkan dengan menggunakan permintaan HTTP sebagai panggilan tidak sinkron.

Dengan pengaturan batas waktu curl diatur ke 1 dan menggunakan session_id yang sama untuk proses yang Anda ingin dikaitkan satu sama lain, Anda dapat berkomunikasi dengan variabel sesi seperti dalam contoh saya di bawah ini. Dengan metode ini Anda bahkan dapat menutup browser Anda dan proses bersamaan masih ada di server.

Jangan lupa untuk memverifikasi ID sesi yang benar seperti ini:

http: //localhost/test/verifysession.php? sessionid = [the id yang benar]

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

Meskipun Anda tidak dapat utas, Anda memiliki beberapa tingkat kendali proses di php. Dua set fungsi yang berguna di sini adalah:

Fungsi kontrol proses http://www.php.net/manual/en/ref.pcntl.php

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

Anda bisa melakukan proses fork dengan pcntl_fork - mengembalikan PID anak. Kemudian Anda dapat menggunakan posix_kill untuk menolak PID itu.

Yang mengatakan, jika Anda membunuh proses orang tua sinyal harus dikirim ke proses anak mengatakan itu untuk mati. Jika php sendiri tidak mengenalinya, Anda bisa mendaftarkan fungsi untuk mengelolanya dan melakukan exit bersih menggunakan pcntl_signal.

Saya tahu ini adalah pertanyaan lama tetapi bagi orang yang mencari, ada ekstensi PECL yang ditulis dalam C yang memberikan PHP kemampuan multi-threading sekarang, ia berada di sini https://github.com/ krakjoe/pthreads

Anda bisa mensimulasikan threading. PHP dapat menjalankan proses latar belakang melalui popen (atau proc_open). Proses-proses tersebut dapat dikomunikasikan melalui stdin dan stdout. Tentu saja proses-proses itu sendiri dapat menjadi program php. Itu mungkin sedekat yang Anda dapatkan.

Anda dapat menggunakan exec () untuk menjalankan skrip baris perintah (seperti php baris perintah), dan jika Anda menyalurkan output ke file, skrip Anda tidak akan menunggu perintah selesai.

Saya tidak begitu ingat sintaks php CLI, tetapi Anda menginginkan sesuatu seperti:

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

Saya pikir beberapa server hosting bersama memiliki exec () dinonaktifkan secara default untuk alasan keamanan, tetapi mungkin patut dicoba.

Bagaimana dengan pcntl_fork?

lihat halaman manual kami untuk contoh: PHP pcntl_fork

Bergantung pada apa yang Anda coba lakukan, Anda juga bisa menggunakan curl_multi untuk mencapainya.

Saya tahu ini sudah terlalu tua, tetapi Anda bisa melihat http://phpthreadlib.sourceforge.net/

Ini mendukung komunikasi dua arah yang bersifat dua arah dan juga memiliki perlindungan untuk membunuh anak-anak (mencegah anak yatim).

pcntl_fork tidak akan berfungsi di lingkungan server web jika telah safe mode dihidupkan. Dalam hal ini, itu hanya akan berfungsi dalam versi CLI PHP.

Anda dapat memiliki opsi:

  1. multi_curl
  2. Seseorang dapat menggunakan perintah sistem untuk hal yang sama
  3. Skenario ideal adalah, buat fungsi threading dalam bahasa C dan kompilasi/konfigurasikan dalam PHP. Sekarang fungsi itu akan menjadi fungsi PHP.

Pada saat penulisan komentar saya saat ini, saya tidak tahu tentang utas PHP. Saya datang untuk mencari sendiri jawabannya di sini, tetapi satu solusi adalah program PHP yang menerima permintaan dari server web mendelegasikan seluruh jawaban formulasi ke aplikasi konsol yang menyimpan outputnya, jawaban untuk request, ke file biner dan program PHP yang meluncurkan aplikasi konsol mengembalikan file biner tersebut byte-by-byte sebagai jawaban atas permintaan yang diterima. Aplikasi konsol dapat ditulis dalam bahasa pemrograman apa pun yang berjalan di server, termasuk yang memiliki dukungan threading yang tepat, termasuk program C++ yang menggunakan OpenMP.

Satu trik yang tidak dapat diandalkan, kotor, adalah menggunakan PHP untuk menjalankan aplikasi konsol, "uname",

uname -a

dan cetak output dari perintah konsol itu ke output HTML untuk mengetahui versi yang tepat dari perangkat lunak server. Kemudian instal versi yang sama persis dari perangkat lunak ke instance VirtualBox, kompilasi/kumpulkan biner yang sepenuhnya mandiri, lebih disukai statis, yang diinginkan dan kemudian unggah ke server. Dari titik itu dan seterusnya, aplikasi PHP dapat menggunakan binari-binari tersebut dalam peran aplikasi konsol yang memiliki multi-threading yang tepat. Ini adalah solusi yang kotor, tidak dapat diandalkan, solusi untuk suatu situasi, ketika administrator server belum menginstal semua implementasi bahasa pemrograman yang diperlukan ke server. Hal yang harus diperhatikan adalah bahwa pada setiap permintaan aplikasi PHP menerima aplikasi konsol berakhir/keluar/get_killed.

Mengenai apa yang dipikirkan oleh administrator layanan hosting tentang pola penggunaan server seperti itu, saya kira itu bermuara pada budaya. Di Eropa Utara penyedia layanan HARUS MEMBERIKAN APA YANG DI IKLAN dan jika eksekusi perintah konsol diizinkan dan mengunggah file non-malware diizinkan dan penyedia layanan memiliki hak untuk membunuh proses server apa pun setelah beberapa menit atau bahkan setelah 30 detik , maka administrator layanan hosting tidak memiliki argumen untuk membentuk keluhan yang tepat. Di Amerika Serikat dan Eropa Barat situasi/budaya sangat berbeda dan saya percaya bahwa ada peluang besar bahwa di AS dan/atau Eropa Barat penyedia layanan hosting akan menolak untuk melayani klien layanan hosting yang menggunakan trik yang dijelaskan di atas. Itu hanya dugaan saya, mengingat pengalaman pribadi saya dengan layanan hosting A.S. dan memberikan apa yang saya dengar dari orang lain tentang layanan hosting Eropa Barat. Pada saat menulis komentar saya saat ini (2018_09_01) saya tidak tahu apa-apa tentang norma-norma budaya penyedia layanan hosting Eropa Selatan, administrator jaringan Eropa Selatan.