2012-03-13 15 views
7

में फ़ंक्शन निष्पादित करना मेरे पास एक ऐसा फ़ंक्शन है जिसे किसी सरणी से लगभग 20K पंक्तियों में जाने की आवश्यकता होती है, और प्रत्येक को बाहरी स्क्रिप्ट लागू होती है। यह एक धीमी प्रक्रिया है, क्योंकि PHP अगली पंक्ति के साथ जारी रखने से पहले स्क्रिप्ट को निष्पादित करने की प्रतीक्षा कर रहा है।समांतर

इस प्रक्रिया को तेज़ी से बनाने के लिए, मैं एक ही समय में विभिन्न हिस्सों में फ़ंक्शन चलाने पर विचार कर रहा था। तो, उदाहरण के लिए, एक समारोह के रूप में 0 से 2000 पंक्तियां, 2001 से 4000 किसी अन्य पर, और इसी तरह। मैं इसे साफ तरीके से कैसे कर सकता हूं? मैं विभिन्न क्रॉन नौकरियों को बना सकता हूं, प्रत्येक समारोह के लिए अलग-अलग पैराम के साथ: myFunction(0, 2000), फिर myFunction(2001, 4000) आदि के साथ एक और क्रॉन नौकरी, लेकिन यह बहुत साफ नहीं लगता है। ऐसा करने का एक अच्छा तरीका क्या है?

+1

मैं एक बार इसी तरह की स्थिति में था। मैंने पाया कि फोर्किंग पीएचपी में दर्दनाक था इसलिए मैंने इसे बाश में किया। स्क्रिप्ट के प्रत्येक उदाहरण के लिए प्रारंभ और रोक के तर्क पारित किए गए और उन्हें सर्वर पर पृष्ठभूमि में चलाया। Exec वह है जिसे आप ढूंढ रहे हैं मुझे विश्वास है। – Jake

उत्तर

6

यदि आप PHP में समांतर कार्यों को निष्पादित करना चाहते हैं, तो मैं Gearman का उपयोग करने पर विचार करूंगा। एक अन्य दृष्टिकोण pcntl_fork() का उपयोग करना होगा, लेकिन जब यह कार्य आधारित होता है तो मैं वास्तविक श्रमिकों को प्राथमिकता दूंगा।

+0

अगर मुझे php config (आईएम 'साझा सर्वर पर) तक पहुंच नहीं है तो आप मुझे कैसे करने के लिए सुझाव देंगे? – Oliver

0

pcntl_fork पर एक नज़र डालें। यह आपको बाल प्रक्रियाओं को जन्म देने की अनुमति देता है जो आपको आवश्यक अलग-अलग काम कर सकता है।

0

सुनिश्चित नहीं है कि आपकी स्थिति का समाधान है लेकिन आप सिस्टम कॉल के आउटपुट को फ़ाइल में रीडायरेक्ट कर सकते हैं, इस प्रकार PHP प्रोग्राम समाप्त होने तक प्रतीक्षा नहीं करेगा। हालांकि इसके परिणामस्वरूप आपके सर्वर को अधिभारित किया जा सकता है।

http://www.php.net/manual/en/function.exec.php - यदि इस फ़ंक्शन के साथ कोई प्रोग्राम प्रारंभ होता है, तो पृष्ठभूमि में चलना जारी रखने के लिए, प्रोग्राम का आउटपुट फ़ाइल या अन्य आउटपुट स्ट्रीम पर रीडायरेक्ट किया जाना चाहिए। ऐसा करने में विफल होने से कार्यक्रम समाप्त होने तक PHP को लटका दिया जाएगा।

+0

लिंक दुर्भाग्य से मर चुका है। –

+0

लिंक @DaveCarruthers अपडेट किया गया – Michal

6

डेटा प्राप्त करने और डेटा को प्रोसेस करने के बीच आप केवल एक ही प्रतीक्षा समय पीड़ित हैं। डेटा को प्रोसेस करना वास्तव में पूरी तरह से अवरुद्ध कर रहा है (आपको बस इसके लिए इंतजार करना होगा)। आपके पास होने वाले कोर की संख्या में प्रक्रियाओं की संख्या बढ़ाने से पहले आपको कोई लाभ नहीं मिलेगा। असल में मुझे लगता है कि इसका मतलब है कि प्रक्रियाओं की संख्या छोटी है इसलिए 2-8 प्रक्रियाओं के निष्पादन को शेड्यूल करना उस भयानक ध्वनि को नहीं लगता है। यदि आप डेटा पुनर्प्राप्त करते समय डेटा को संसाधित करने में सक्षम नहीं होने के बारे में चिंतित हैं, तो आप सिद्धांत रूप से छोटे डेटा में डेटाबेस से अपना डेटा प्राप्त कर सकते हैं, और उसके बाद प्रोसेस लोड को कुछ प्रक्रियाओं के बीच वितरित कर सकते हैं, प्रत्येक कोर के लिए एक।

मुझे लगता है कि मैं प्रसंस्करण धागे को चलाने के लिए फोर्किंग बाल प्रक्रिया दृष्टिकोण के साथ अधिक संरेखित करता हूं। वहाँ pcntl_fork दस्तावेज़ पृष्ठ पर टिप्पणी में एक शानदार प्रदर्शन एक नौकरी डेमॉन वर्ग

http://php.net/manual/en/function.pcntl-fork.php

<?php 
declare(ticks=1); 
//A very basic job daemon that you can extend to your needs. 
class JobDaemon{ 

    public $maxProcesses = 25; 
    protected $jobsStarted = 0; 
    protected $currentJobs = array(); 
    protected $signalQueue=array(); 
    protected $parentPID; 

    public function __construct(){ 
     echo "constructed \n"; 
     $this->parentPID = getmypid(); 
     pcntl_signal(SIGCHLD, array($this, "childSignalHandler")); 
    } 

    /** 
    * Run the Daemon 
    */ 
    public function run(){ 
     echo "Running \n"; 
     for($i=0; $i<10000; $i++){ 
      $jobID = rand(0,10000000000000); 

      while(count($this->currentJobs) >= $this->maxProcesses){ 
       echo "Maximum children allowed, waiting...\n"; 
       sleep(1); 
      } 

      $launched = $this->launchJob($jobID); 
     } 

     //Wait for child processes to finish before exiting here 
     while(count($this->currentJobs)){ 
      echo "Waiting for current jobs to finish... \n"; 
      sleep(1); 
     } 
    } 

    /** 
    * Launch a job from the job queue 
    */ 
    protected function launchJob($jobID){ 
     $pid = pcntl_fork(); 
     if($pid == -1){ 
      //Problem launching the job 
      error_log('Could not launch new job, exiting'); 
      return false; 
     } 
     else if ($pid){ 
      // Parent process 
      // Sometimes you can receive a signal to the childSignalHandler function before this code executes if 
      // the child script executes quickly enough! 
      // 
      $this->currentJobs[$pid] = $jobID; 

      // In the event that a signal for this pid was caught before we get here, it will be in our signalQueue array 
      // So let's go ahead and process it now as if we'd just received the signal 
      if(isset($this->signalQueue[$pid])){ 
       echo "found $pid in the signal queue, processing it now \n"; 
       $this->childSignalHandler(SIGCHLD, $pid, $this->signalQueue[$pid]); 
       unset($this->signalQueue[$pid]); 
      } 
     } 
     else{ 
      //Forked child, do your deeds.... 
      $exitStatus = 0; //Error code if you need to or whatever 
      echo "Doing something fun in pid ".getmypid()."\n"; 
      exit($exitStatus); 
     } 
     return true; 
    } 

    public function childSignalHandler($signo, $pid=null, $status=null){ 

     //If no pid is provided, that means we're getting the signal from the system. Let's figure out 
     //which child process ended 
     if(!$pid){ 
      $pid = pcntl_waitpid(-1, $status, WNOHANG); 
     } 

     //Make sure we get all of the exited children 
     while($pid > 0){ 
      if($pid && isset($this->currentJobs[$pid])){ 
       $exitCode = pcntl_wexitstatus($status); 
       if($exitCode != 0){ 
        echo "$pid exited with status ".$exitCode."\n"; 
       } 
       unset($this->currentJobs[$pid]); 
      } 
      else if($pid){ 
       //Oh no, our job has finished before this parent process could even note that it had been launched! 
       //Let's make note of it and handle it when the parent process is ready for it 
       echo "..... Adding $pid to the signal queue ..... \n"; 
       $this->signalQueue[$pid] = $status; 
      } 
      $pid = pcntl_waitpid(-1, $status, WNOHANG); 
     } 
     return true; 
    } 
} 
2

आप "pthreads" का उपयोग कर सकते

बहुत स्थापित करने के लिए आसान है और काम करता है महान के एक कार्यान्वयन दिखा है खिड़कियों पर यहां से

डाउनलोड ->http://windows.php.net/downloads/pecl/releases/pthreads/2.0.4/

ज़िप फ़ाइल निकालें और फिर

  • फ़ाइल 'php_pthreads.dll' को php \ ext \ निर्देशिका में ले जाएं।

  • फ़ाइल 'pthreadVC2.dll' को php \ निर्देशिका में ले जाएं।फ़ाइल को बचाने

    extension=php_pthreads.dll 
    

    :

फिर अपने 'php.ini' फ़ाइल में इस पंक्ति जोड़ें। अधिक जानकारी के लिए

class ChildThread extends Thread { 
    public $data; 

    public function run() { 
     /* Do some expensive work */ 

     $this->data = 'result of expensive work'; 
    } 
} 

$thread = new ChildThread(); 

if ($thread->start()) {  
    /* 
    * Do some expensive work, while already doing other 
    * work in the child thread. 
    */ 

    // wait until thread is finished 
    $thread->join(); 

    // we can now even access $thread->data 
} 

के बारे में pthreads php डॉक्स यहां पढ़ें::

तुम सिर्फ :-)

किया अब यह कैसे उपयोग करने के लिए की मिसाल देखने को मिलती हैं

PHP DOCS PTHREADS

  • यदि आप मेरे जैसे WAMP का उपयोग कर रहे हैं, तो आपको 'pthreadVC2.dll' जोड़ना चाहिए \ WAMP \ बिन \ अपाचे \ ApacheX.XX \ बिन में और भी 'php.ini' फ़ाइल (समान पथ) को संपादित करें और के रूप में एक ही पंक्ति जोड़ने से पहले

    विस्तार = php_pthreads.dll

अच्छा लकीर!