PHP में अतुल्यकालिक फ़ंक्शन कॉल


86

मैं एक PHP वेब अनुप्रयोग पर काम कर रहा हूं और मुझे अनुरोध में कुछ नेटवर्क संचालन करने की आवश्यकता है जैसे कि उपयोगकर्ता के अनुरोध के आधार पर दूरस्थ सर्वर से किसी को लाने के लिए।

क्या पीएचपी में अतुल्यकालिक व्यवहार को अनुकरण करना संभव है, यह देखते हुए कि मुझे एक फ़ंक्शन के लिए कुछ डेटा पास करना होगा और इससे आउटपुट की भी आवश्यकता होगी।

मेरा कोड इस प्रकार है:

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

प्रत्येक नेटवर्क ऑपरेशन को मेरे आवेदन के प्रतिक्रिया समय में कुल 15 सेकंड जोड़ने के लिए लगभग 5 सेकंड लगते हैं, जबकि मैंने 3 अनुरोध किए हैं।

MakeNetworkCall () फ़ंक्शन केवल एक HTTP POST अनुरोध करता है।

रिमोट सर्वर एक 3 पार्टी एपीआई है इसलिए मुझे वहां पर कोई नियंत्रण नहीं है।

पुनश्च: कृपया AJAX या अन्य चीजों के बारे में सुझाव देने का जवाब न दें। मैं वर्तमान में देख रहा हूँ कि क्या मैं PHP के माध्यम से ऐसा कर सकता हूँ C ++ एक्सटेंशन या ऐसा ही कुछ।


CURLआग अनुरोधों का उपयोग करने का प्रयास करें और वेब से कुछ डेटा प्राप्त करें ...
बोगडान बर्म

मेरा मानना ​​है कि उत्तर यहां दिया गया है: stackoverflow.com/questions/13846192/… त्वरित नोट: थ्रेडिंग का उपयोग करें
DRAX


गैर-अवरोधक कोड को चलाने के लिए आप PHP के stream_select फ़ंक्शन का उपयोग कर सकते हैं । React इसका उपयोग नोड के समान एक घटना-चालित लूप बनाने के लिए करता है
क्विन कॉमेंडेंट

जवाबों:


20

आजकल, यह उपयोग करने के लिए बेहतर है कतारों धागे से (जो Laravel का प्रयोग नहीं करते के लिए वहाँ अन्य कार्यान्वयन की टन कर रहे हैं इस तरह )।

मूल विचार है, आपकी मूल PHP स्क्रिप्ट कार्यों या नौकरियों को एक कतार में रखती है। फिर आपके पास कतार में काम करने वाले श्रमिक कहीं और दौड़ रहे हैं, कतार से बाहर नौकरी ले रहे हैं और उन्हें मूल PHP के स्वतंत्र रूप से संसाधित करना शुरू कर रहे हैं।

लाभ हैं:

  1. स्केलेबिलिटी - आप मांग के साथ काम करने के लिए वर्कर नोड जोड़ सकते हैं। इस तरह, कार्यों को समानांतर में चलाया जाता है।
  2. विश्वसनीयता - आधुनिक कतार प्रबंधक जैसे कि RabbitMQ, ZeroMQ, Redis, आदि को अत्यंत विश्वसनीय बनाया जाता है।


8

मेरा सीधा जवाब नहीं है, लेकिन आप इन बातों पर गौर करना चाहते हैं:

  • रीकॉइल प्रोजेक्ट - https://github.com/recoilphp/recoil
  • php का LibEvent एक्सटेंशन? http://www.php.net/manual/en/book.libevent.php
  • http://www.php.net/manual/en/function.pcntl-fork.php forking की प्रक्रिया
  • संदेश दलाल, यानी आप HTTP कॉल करने के लिए श्रमिकों को शुरू कर सकते हैं और एक बार jobऐसा करने के बाद, कैश किए गए HTTP प्रतिक्रिया निकाय को संसाधित करने के लिए उस कार्य का वर्णन करते हुए एक नया काम डालें।

3

CURL यहां आपकी एकमात्र वास्तविक पसंद होने जा रही है (या तो, या गैर-ब्लॉकिंग सॉकेट्स और कुछ कस्टम लॉजिक का उपयोग करके)।

यह लिंक आपको सही दिशा में भेजना चाहिए। PHP में कोई अतुल्यकालिक प्रसंस्करण नहीं है, लेकिन यदि आप एक साथ कई वेब अनुरोध करने का प्रयास कर रहे हैं, तो cURL मल्टी आपके लिए इसका ख्याल रखेगा।


2

मुझे लगता है कि अगर HTML और अन्य UI सामानों को वापस लौटाए जाने वाले डेटा की आवश्यकता है, तो इसे async करने का कोई तरीका नहीं है।

मेरा मानना ​​है कि PHP में ऐसा करने का एकमात्र तरीका एक डेटाबेस में एक अनुरोध को लॉग इन करना होगा और हर मिनट में क्रोन की जांच करना होगा, या गियरमैन कतार प्रसंस्करण जैसी किसी चीज़ का उपयोग करना होगा, या हो सकता है कि एक कमांड लाइन प्रक्रिया निष्पादित करें ()

इस बीच में आपको php पेज में कुछ html या js उत्पन्न करने होंगे जो इसे प्रगति पर जाँचने के लिए हर कुछ सेकंड में पुनः लोड करता है, आदर्श नहीं।

मुद्दे को दरकिनार करने के लिए, आप कितने अलग-अलग अनुरोधों की अपेक्षा कर रहे हैं? क्या आप उन सभी को स्वचालित रूप से हर घंटे डाउनलोड कर सकते हैं और डेटाबेस में सहेज सकते हैं?



0

मुझे लगता है कि यहाँ CURL समाधान के बारे में कुछ कोड की आवश्यकता है, इसलिए मैं इसे साझा करूंगा (इसे कई स्रोतों को PHP मैनुअल और टिप्पणियों के रूप में मिलाकर लिखा गया था)।

यह कुछ समानांतर HTTP अनुरोधों (डोमेन में $aURLs) करता है और हर एक के पूरा होने पर प्रतिक्रियाओं को प्रिंट करता है (और उन्हें $doneअन्य संभावित उपयोगों के लिए संग्रहीत किया जाता है )।

कोड जरूरत से ज्यादा लंबा है क्योंकि रियलटाइम प्रिंट भाग और टिप्पणियों की अधिकता है, लेकिन इसे बेहतर बनाने के लिए उत्तर को संपादित करने के लिए स्वतंत्र महसूस करें:

<?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
?>

0

एक तरीका pcntl_fork()एक पुनरावर्ती कार्य में उपयोग करना है।

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

इसके बारे pcntl_fork()में एक बात यह है कि अपाचे के रास्ते से स्क्रिप्ट चलाते समय, यह काम नहीं करता है (यह अपाचे द्वारा समर्थित नहीं है)। तो, उस मुद्दे को हल करने का एक तरीका php cli का उपयोग करके स्क्रिप्ट को चलाना है, जैसे: exec('php fork.php',$output);किसी अन्य फ़ाइल से। ऐसा करने के लिए आपके पास दो फाइलें होंगी: एक जो अपाचे द्वारा भरी गई है और एक जो exec()अपाचे द्वारा लोड की गई फ़ाइल के अंदर से इस तरह से चल रही है:

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);
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.