2013-03-02 32 views
-4

我的PHP代碼包含許多foreach循環,並且結果絕對是災難性的。運行時間太長。優化使用大量for循環的PHP代碼

是否有替代方案。我接受所有建議。

我在想,可能會實現基於Flash的客戶端,並使用actionscript來利用客戶端的CPU來運行邏輯。

或者有沒有辦法使用C/C++來處理服務器本身對計算要求較高的部分,並返回PHP的結果。

以下函數被調用1,000,000次。

public function performEnrichmentAnalysis($geneSet) { 
    /** 
    * $mainArray is a multi dimentional array. 
    * EntrezID | Set (0/1) | pValue | rank 
    */ 
    $mainArray = array(); 
    $finalArray = array(); 
    $originalGenesScore = 0; 
    $randomGenesScore = 0; 
    $u = 0; 
    $EntrezID = array(); 
    $Set = array(); 
    $pValue = array(); 
    $Rank = array(); 
    $originalGenes = $geneSet->getGenes(); 
    $memeberCount = $geneSet->getGeneCount(); 
    $randomGenes = $this->geneExpressionData->getRandomGenes($memeberCount); 
    /** 
    * Copy the elements of original and random gene sets to main array. 
    */ 
    foreach ($originalGenes as $key => $value) { 
     $pVal = $this->geneExpressionData->getExpressionValue($value); 
     $array = array('EntrezID' => $value, 'Set' => 0, 'pValue' => $pVal, 'Rank' => 999); 
     array_push($mainArray, $array); 
     unset($array); 
    } 
    foreach ($randomGenes as $key => $value) { 
     $pVal = $this->geneExpressionData->getExpressionValue($value); 
     $array = array('EntrezID' => $value, 'Set' => 1, 'pValue' => $pVal, 'Rank' => 999); 
     array_push($mainArray, $array); 
     unset($array); 
    } 
    /** 
    * sort the multi dimentaional array based on p-values 
    */ 
    foreach ($mainArray as $key => $row) { 
     $EntrezID[$key] = $row['EntrezID']; 
     $Set[$key] = $row['Set']; 
     $pValue[$key] = $row['pValue']; 
     $Rank[$key] = $row['Rank']; 
    } 
    array_multisort($pValue, SORT_ASC, $mainArray); 

    /** 
    * Assign ranks to the genes 
    */ 
    for ($index = 0; $index < count($mainArray); $index++) { 
     $row = $mainArray[$index]; 
     $row['Rank'] = $index + 1; 
     $row['Score'] = 0; 
     //print_r($row['Rank']); 
     array_push($finalArray, $row); 
    } 

    /** 
    * Calculate scores for each gene 
    */ 
    for ($i = 0; $i < count($finalArray); $i++) { 
     for ($j = $i + 1; $j < count($finalArray); $j++) { 
      if ($finalArray[$j]['Set'] != $finalArray[$i]['Set']) { 
       $finalArray[$i]['Score']++; 
      } 
     } 
    } 

    /** 
    * Calculate score for the entire set and get universal U and z score. 
    */ 
    for ($counter = 0; $counter < count($finalArray); $counter++) { 
     if ($finalArray[$counter]['Set'] == 0) { 
      $originalGenesScore += $finalArray[$counter]['Score']; 
     } 
     if ($finalArray[$counter]['Set'] == 1) { 
      $randomGenesScore += $finalArray[$counter]['Score']; 
     } 
    } 

    if ($originalGenesScore > $randomGenesScore) { 
     $u = $randomGenesScore; 
    } else { 
     $u = $originalGenesScore; 
    } 

    $zNumerator = $u - (($memeberCount * $memeberCount)/(2)); 
    $zDenominatorSquared = ($memeberCount * $memeberCount * ($memeberCount + $memeberCount + 1))/12; 

    $z = $zNumerator/sqrt($zDenominatorSquared); 

    if (abs($z) > 2.303) { 
     $this->temp001++; 
    } elseif (abs($z) > 1.605) { 
     $this->temp005++; 
    } else { 
     $this->tempRemaining++; 
    } 
} 
+1

我們需要看到代碼,如果你想我們tobhelp你優化。 Alo代碼優化可能更多關於[代碼評論](http://codereview.stackexchange.com)主題 – 2013-03-02 21:18:26

+1

我覺得你的問題有點太模糊。你沒有告訴我們關於你在這些循環中遍歷的數據以及你正在運行的計算的任何信息。 – 2013-03-02 21:19:27

+0

對,謝謝。我現在發佈了代碼。 – Pranjal 2013-03-02 21:24:01

回答

2

那麼,這不是真的可以輕鬆回答的問題。是的,假設你知道C++,代碼可以用C++重寫。我沒有看到任何重大障礙。

您將不得不想出一種方法將原始geneSet轉換爲C++代碼,然後構造一個表示您的$mainArray等的結構。使用std::vector爲您的陣列。

由於這段代碼本身並不實際生成任何webcontent,因此可以很容易地將該函數替換爲對服務器上安裝的C++程序的調用。我建議你實際上實現了在C++中調用這個函數的功能,因爲如果這被稱爲1M次,那麼你最好在C++中進行1M次調用,而不是在1M次調用一段C++代碼。

+0

謝謝Mats Peterson 我是PHP和客戶端 - 服務器開發新手。我將用C++重寫這個,並從C++程序中調用,但我不清楚如何從PHP調用C++代碼。我想從PHP代碼發送一個鏈表和一個數組到C++類,它將工作,然後返回一個數組。 我應該遵循什麼步驟? – Pranjal 2013-03-03 04:05:02

+0

我假設調用這個函數1M次需要幾秒鐘,對吧?因此,將輸入數據寫入文件是非常合理的,使用'exec()'[或某些類似的PHP函數]來執行C++程序,並將輸出結果提供給文件(或「stdout」)可以被捕獲)。 – 2013-03-03 12:44:20

+0

謝謝你的幫助。我會試試這個。 – Pranjal 2013-03-03 16:50:22