Saya sedang mengerjakan aplikasi web PHP dan saya perlu melakukan beberapa operasi jaringan dalam permintaan seperti mengambil seseorang dari server jarak jauh berdasarkan permintaan pengguna.
Apakah mungkin untuk mensimulasikan perilaku asynchronous dalam PHP mengingat bahwa saya harus meneruskan beberapa data ke suatu fungsi dan juga memerlukan keluaran darinya.
Kode saya seperti:
<?php
$data1 = processGETandPOST();
$data2 = processGETandPOST();
$data3 = processGETandPOST();
$response1 = makeNetworkCall($data1);
$response2 = makeNetworkCall($data2);
$response3 = makeNetworkCall($data3);
processNetworkResponse($response1);
processNetworkResponse($response2);
processNetworkResponse($response3);
/*HTML and OTHER UI STUFF HERE*/
exit;
?>
Setiap operasi jaringan membutuhkan waktu sekitar 5 detik untuk menyelesaikan penambahan total 15 detik ke waktu respons aplikasi saya karena saya membuat 3 permintaan.
Fungsi makeNetworkCall () hanya melakukan permintaan HTTP POST.
Server jarak jauh adalah API pihak ketiga jadi saya tidak memiliki kendali apa pun di sana.
PS: Mohon tidak menjawab memberikan saran tentang AJAX atau hal-hal lain. Saat ini saya sedang mencari apakah saya dapat melakukan ini melalui PHP mungkin dengan ekstensi C ++ atau sesuatu seperti itu.
sumber
CURL
untuk mengaktifkan permintaan dan mengambil beberapa data dari web ...Jawaban:
Saat ini, lebih baik menggunakan antrian daripada utas (bagi mereka yang tidak menggunakan Laravel, ada banyak implementasi lain di luar sana seperti ini ).
Ide dasarnya adalah, skrip PHP asli Anda menempatkan tugas atau pekerjaan ke dalam antrian. Kemudian Anda memiliki pekerja pekerjaan antrian yang berjalan di tempat lain, mengambil pekerjaan dari antrian dan mulai memprosesnya secara independen dari PHP asli.
Keunggulannya adalah:
sumber
Saya tidak memiliki jawaban langsung, tetapi Anda mungkin ingin melihat hal-hal ini:
job
selesai, masukkan pekerjaan baru yang menjelaskan pekerjaan yang perlu dilakukan untuk memproses isi tanggapan HTTP yang di-cache.sumber
cURL akan menjadi satu-satunya pilihan nyata Anda di sini (baik itu, atau menggunakan soket non-pemblokiran dan beberapa logika khusus).
Tautan ini akan mengarahkan Anda ke arah yang benar. Tidak ada pemrosesan asinkron dalam PHP, tetapi jika Anda mencoba membuat beberapa permintaan web secara bersamaan, cURL multi akan mengurusnya untuk Anda.
sumber
Saya pikir jika HTML dan UI lainnya membutuhkan data yang dikembalikan maka tidak akan ada cara untuk melakukan asinkronisasi.
Saya percaya satu-satunya cara untuk melakukan ini di PHP adalah dengan mencatat permintaan dalam database dan melakukan pemeriksaan cron setiap menit, atau menggunakan sesuatu seperti pemrosesan antrian Gearman, atau mungkin exec () proses baris perintah
Sementara itu, halaman php Anda harus membuat beberapa html atau js yang membuatnya dimuat ulang setiap beberapa detik untuk memeriksa kemajuan, tidak ideal.
Untuk menghindari masalah, berapa banyak permintaan berbeda yang Anda harapkan? Bisakah Anda mendownload semuanya secara otomatis setiap satu jam atau lebih dan menyimpannya ke database?
sumber
Pertanyaan lama ini punya jawaban baru. Ada beberapa solusi "async" untuk PHP hari ini (yang setara dengan multiproses Python dalam arti mereka menelurkan proses PHP independen baru daripada mengelolanya di tingkat kerangka kerja)
Dua solusi yang telah saya lihat adalah
Cobalah!
sumber
Ada juga http v2 yang merupakan pembungkus untuk curl. Bisa di install via pecl.
http://devel-m6w6.rhcloud.com/mdref/http/
sumber
Saya pikir beberapa kode tentang solusi cURL diperlukan di sini, jadi saya akan membagikan milik saya (ditulis mencampurkan beberapa sumber sebagai Manual PHP dan komentar).
Itu melakukan beberapa permintaan HTTP paralel (domain di
$aURLs
) dan mencetak tanggapan setelah masing-masing selesai (dan menyimpannya di$done
untuk kemungkinan penggunaan lain).Kode lebih panjang dari yang dibutuhkan karena bagian cetak waktu nyata dan kelebihan komentar, tetapi jangan ragu untuk mengedit jawaban untuk memperbaikinya:
<?php /* Strategies to avoid output buffering, ignore the block if you don't want to print the responses before every cURL is completed */ ini_set('output_buffering', 'off'); // Turn off output buffering ini_set('zlib.output_compression', false); // Turn off PHP output compression //Flush (send) the output buffer and turn off output buffering ob_end_flush(); while (@ob_end_flush()); apache_setenv('no-gzip', true); //prevent apache from buffering it for deflate/gzip ini_set('zlib.output_compression', false); header("Content-type: text/plain"); //Remove to use HTML ini_set('implicit_flush', true); // Implicitly flush the buffer(s) ob_implicit_flush(true); header('Cache-Control: no-cache'); // recommended to prevent caching of event data. $string=''; for($i=0;$i<1000;++$i){$string.=' ';} output($string); //Safari and Internet Explorer have an internal 1K buffer. //Here starts the program output function output($string){ ob_start(); echo $string; if(ob_get_level()>0) ob_flush(); ob_end_clean(); // clears buffer and closes buffering flush(); } function multiprint($aCurlHandles,$print=true){ global $done; // iterate through the handles and get your content foreach($aCurlHandles as $url=>$ch){ if(!isset($done[$url])){ //only check for unready responses $html = curl_multi_getcontent($ch); //get the content if($html){ $done[$url]=$html; if($print) output("$html".PHP_EOL); } } } }; function full_curl_multi_exec($mh, &$still_running) { do { $rv = curl_multi_exec($mh, $still_running); //execute the handles } while ($rv == CURLM_CALL_MULTI_PERFORM); //CURLM_CALL_MULTI_PERFORM means you should call curl_multi_exec() again because there is still data available for processing return $rv; } set_time_limit(60); //Max execution time 1 minute $aURLs = array("http://domain/script1.php","http://domain/script2.php"); // array of URLs $done=array(); //Responses of each URL //Initialization $aCurlHandles = array(); // create an array for the individual curl handles $mh = curl_multi_init(); // init the curl Multi and returns a new cURL multi handle foreach ($aURLs as $id=>$url) { //add the handles for each url $ch = curl_init(); // init curl, and then setup your options curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER,1); // returns the result - very important curl_setopt($ch, CURLOPT_HEADER, 0); // no headers in the output $aCurlHandles[$url] = $ch; curl_multi_add_handle($mh,$ch); } //Process $active = null; //the number of individual handles it is currently working with $mrc=full_curl_multi_exec($mh, $active); //As long as there are active connections and everything looks OK… while($active && $mrc == CURLM_OK) { //CURLM_OK means is that there is more data available, but it hasn't arrived yet. // Wait for activity on any curl-connection and if the network socket has some data… if($descriptions=curl_multi_select($mh,1) != -1) {//If waiting for activity on any curl_multi connection has no failures (1 second timeout) usleep(500); //Adjust this wait to your needs //Process the data for as long as the system tells us to keep getting it $mrc=full_curl_multi_exec($mh, $active); //output("Still active processes: $active".PHP_EOL); //Printing each response once it is ready multiprint($aCurlHandles); } } //Printing all the responses at the end //multiprint($aCurlHandles,false); //Finalize foreach ($aCurlHandles as $url=>$ch) { curl_multi_remove_handle($mh, $ch); // remove the handle (assuming you are done with it); } curl_multi_close($mh); // close the curl multi handler ?>
sumber
Salah satu caranya adalah dengan menggunakan
pcntl_fork()
fungsi rekursif.function networkCall(){ $data = processGETandPOST(); $response = makeNetworkCall($data); processNetworkResponse($response); return true; } function runAsync($times){ $pid = pcntl_fork(); if ($pid == -1) { die('could not fork'); } else if ($pid) { // we are the parent $times -= 1; if($times>0) runAsync($times); pcntl_wait($status); //Protect against Zombie children } else { // we are the child networkCall(); posix_kill(getmypid(), SIGKILL); } } runAsync(3);
Satu hal tentang
pcntl_fork()
adalah bahwa ketika menjalankan skrip dengan Apache, itu tidak berfungsi (tidak didukung oleh Apache). Jadi, salah satu cara untuk mengatasi masalah itu adalah dengan menjalankan skrip menggunakan php cli, seperti:exec('php fork.php',$output);
dari file lain. Untuk melakukan ini, Anda akan memiliki dua file: satu yang dimuat oleh Apache dan satu lagi yang dijalankan denganexec()
dari dalam file yang dimuat oleh Apache seperti ini:apacheLoadedFile.php
exec('php fork.php',$output);
fork.php
function networkCall(){ $data = processGETandPOST(); $response = makeNetworkCall($data); processNetworkResponse($response); return true; } function runAsync($times){ $pid = pcntl_fork(); if ($pid == -1) { die('could not fork'); } else if ($pid) { // we are the parent $times -= 1; if($times>0) runAsync($times); pcntl_wait($status); //Protect against Zombie children } else { // we are the child networkCall(); posix_kill(getmypid(), SIGKILL); } } runAsync(3);
sumber