2016-11-22 31 views
2

我有php7 CLI守護進程,它以超過50M的文件大小順序解析json。我試圖使用pcntl_fork()向mysql分離進程保存每1000條解析數據,對於〜200k行,它工作正常。如何處理pcntl_fork():錯誤35?

然後我得到pcntl_fork():錯誤35

我認爲這是因爲mysql插入變得比分析慢,這會導致生成越來越多的分支,直到CentOS 6.3無法處理它。

有沒有辦法抓住這個錯誤來求助於單進程解析和保存?或者有沒有辦法檢查子進程數?

+0

35訴諸同樣的過程是'EGAIN',這意味着你已經打了進程限制。也許你沒有調用'pcntl_wait'來清理完成後的進程? – Barmar

+0

centos中fork的最大進程數限制是多少?因爲那時它應該是可計算的,200k記錄會發送+/- 200分叉。 「還是有辦法檢查子進程計數」這可以通過保持pid手動完成。一個beter方法將會啓動多個守護進程來獲取一個工作或者運行它proc_open http://php.net/proc_open –

+0

那麼爲什麼分叉可以解決這個問題呢?你正在解析一些數據,然後使用一個單獨的過程同時觸發MySQL - 爲什麼這會成爲解決任何問題的方法?在同一個過程中使用交易有什麼問題?你顯然認爲,如果你分成N個進程,它會快N倍,但不會。現在我們遇到了一個錯誤解決方案的問題,並且解決了這個錯誤的解決方案如果您希望插入速度很快,請在同一事務中對這1000行進行分組。這將花費最少的I/O來編寫。 – Mjh

回答

1

下面是我基於@Sander Visser評論所做的解決方案。關鍵部分是檢查現有的流程,如果有太多

class serialJsonReader{ 

const MAX_CHILD_PROCESSES = 50; 
private $child_processes=[]; //will store alive child PIDs 

private function flushCachedDataToStore() { 

//resort to single process 
    if (count($this->child_processes) > self::MAX_CHILD_PROCESSES) { 
     $this->checkChildProcesses(); 

     $this->storeCollectedData() //main work here 
    } 

//use as much as possible 
    else { 
     $pid = pcntl_fork(); 
     if (!$pid) { 
      $this->storeCollectedData(); //main work here 
      exit(); 
     } 
     elseif ($pid == -1) { 
      die('could not fork'); 
     } 
     else { 
      $this->child_processes[] = $pid; 
      $this->checkChildProcesses(); 
     } 
    } 
} 

private function checkChildProcesses() { 
    if (count($this->child_processes) > self::MAX_CHILD_PROCESSES) { 
     foreach ($this->child_processes as $key => $pid) { 
      $res = pcntl_waitpid($pid, $status, WNOHANG); 

      // If the process has already exited 
      if ($res == -1 || $res > 0) { 
       unset($this->child_processes[$key]); 
      } 
     } 
    } 
} 
}