2015-12-21 64 views
1

我使用這個下面的函數來檢查,如果在自己的位置存在的圖像。每次腳本運行時,它都會加載大約40-50個URL,因此需要很長時間才能加載頁面。我正在考慮將線程用於「for語句」(在腳本的結尾處),但找不到有關如何執行此操作的很多示例。我不是很熟悉php的多線程,但我在這裏找到了一個使用popen的例子。多線程for語句與PHP

我的腳本:

function get_image_dim($sURL) { 

    try { 
    $hSock = @ fopen($sURL, 'rb'); 
    if ($hSock) { 
     while(!feof($hSock)) { 
     $vData = fread($hSock, 300); 
     break; 
     } 
     fclose($hSock); 
     if (strpos(' ' . $vData, 'JFIF')>0) { 
     $vData = substr($vData, 0, 300); 
     $asResult = unpack('H*',$vData);   
     $sBytes = $asResult[1]; 
     $width = 0; 
     $height = 0; 
     $hex_width = ''; 
     $hex_height = ''; 
     if (strstr($sBytes, 'ffc2')) { 
      $hex_height = substr($sBytes, strpos($sBytes, 'ffc2') + 10, 4); 
      $hex_width = substr($sBytes, strpos($sBytes, 'ffc2') + 14, 4); 
     } else { 
      $hex_height = substr($sBytes, strpos($sBytes, 'ffc0') + 10, 4); 
      $hex_width = substr($sBytes, strpos($sBytes, 'ffc0') + 14, 4); 
     } 
     $width = hexdec($hex_width); 
     $height = hexdec($hex_height); 
     return array('width' => $width, 'height' => $height); 
     } elseif (strpos(' ' . $vData, 'GIF')>0) { 
     $vData = substr($vData, 0, 300); 
     $asResult = unpack('h*',$vData); 
     $sBytes = $asResult[1]; 
     $sBytesH = substr($sBytes, 16, 4); 
     $height = hexdec(strrev($sBytesH)); 
     $sBytesW = substr($sBytes, 12, 4); 
     $width = hexdec(strrev($sBytesW)); 
     return array('width' => $width, 'height' => $height); 
     } elseif (strpos(' ' . $vData, 'PNG')>0) { 
     $vDataH = substr($vData, 22, 4); 
     $asResult = unpack('n',$vDataH); 
     $height = $asResult[1];   
     $vDataW = substr($vData, 18, 4); 
     $asResult = unpack('n',$vDataW); 
     $width = $asResult[1];   
     return array('width' => $width, 'height' => $height); 
     } 
    } 
    } catch (Exception $e) {} 
    return FALSE; 
} 

for($y=0;$y<= ($image_count-1);$y++){ 
$dim = get_image_dim($images[$y]); 
    if (empty($dim)) { 
    echo $images[$y]; 
    unset($images[$y]); 
    } 
} 
$images = array_values($images); 

器一起例如我發現:

for ($i=0; $i<10; $i++) { 
    // open ten processes 
    for ($j=0; $j<10; $j++) { 
     $pipe[$j] = popen('script.php', 'w'); 
    } 

    // wait for them to finish 
    for ($j=0; $j<10; ++$j) { 
     pclose($pipe[$j]); 
    } 
} 

我不知道這是我的代碼部件在運行script.php去?我試圖移動整個腳本,但沒有奏效?

我如何能實現這個或者任何想法有一個更好的辦法來多線程呢?謝謝。

+2

你可能想看看使用curl庫和異步設施。 http://www.phpied.com/simultaneuos-http-requests-in-php-with-curl/ – pvg

+1

如果你想要線程,考慮pthreads擴展。如果你只想做異步HTTP請求,考慮curl_multi或http://docs.guzzlephp.org/en/latest/quickstart.html#async-requests – Gordon

回答

1

PHP沒有原生多線程。你可以用pthreads做到這一點,但在那裏有一點經驗,我可以肯定地說,這對你的需求來說太多了。

你最好的選擇將是使用curl,你可以啓動多個請求與curl_multi_init。基於折PHP.net的example,下面可能是你的工作需要:

function curl_multi_callback(Array $urls, $callback, $cache_dir = NULL, $age = 600) { 
    $return = array(); 

    $conn = array(); 

    $max_age = time()-intval($age); 

    $mh = curl_multi_init(); 

    if(is_dir($cache_dir)) { 
     foreach($urls as $i => $url) { 
      $cache_path = $cache_dir.DIRECTORY_SEPARATOR.sha1($url).'.ser'; 
      if(file_exists($cache_path)) { 
       $stat = stat($cache_path); 
       if($stat['atime'] > $max_age) { 
        $return[$i] = unserialize(file_get_contents($cache_path)); 
        unset($urls[$i]); 
       } else { 
        unlink($cache_path); 
       } 
      } 
     } 
    } 

    foreach ($urls as $i => $url) { 
     $conn[$i] = curl_init($url); 
     curl_setopt($conn[$i], CURLOPT_RETURNTRANSFER, 1); 
     curl_multi_add_handle($mh, $conn[$i]); 
    } 

    do { 
     $status = curl_multi_exec($mh, $active); 
     // Keep attempting to get info so long as we get info 
     while (($info = curl_multi_info_read($mh)) !== FALSE) { 
      // We received information from Multi 
      if (false !== $info) { 
       // The connection was successful 
       $handle = $info['handle']; 
       // Find the index of the connection in `conn` 
       $i = array_search($handle, $conn); 
       if($info['result'] === CURLE_OK) { 
        // If we found an index and that index is set in the `urls` array 
        if(false !== $i && isset($urls[$i])) { 
         $content = curl_multi_getcontent($handle); 
         $return[$i] = $data = array(
          'url'  => $urls[$i], 
          'content' => $content, 
          'parsed' => call_user_func($callback, $content, $urls[$i]), 
         ); 
         if(is_dir($cache_dir)) { 
          file_put_contents($cache_dir.DIRECTORY_SEPARATOR.sha1($urls[$i]).'.ser', serialize($data)); 
         } 
        } 
       } else { 
        // Handle failures how you will 
       } 
       // Close, even if a failure 
       curl_multi_remove_handle($mh, $handle); 
       unset($conn[$i]); 
      } 
     } 
    } while ($status === CURLM_CALL_MULTI_PERFORM || $active); 


    // Cleanup and resolve any remaining connections (unlikely) 
    if(!empty($conn)) { 
     foreach ($conn as $i => $handle) { 
      if(isset($urls[$i])) { 
       $content = curl_multi_getcontent($handle); 
       $return[$i] = $data = array(
        'url'  => $urls[$i], 
        'content' => $content, 
        'parsed' => call_user_func($callback, $content, $urls[$i]), 
       ); 
       if(is_dir($cache_dir)) { 
        file_put_contents($cache_dir.DIRECTORY_SEPARATOR.sha1($urls[$i]).'.ser', serialize($data)); 
       } 
      } 
      curl_multi_remove_handle($mh, $handle); 
      unset($conn[$i]); 
     } 
    } 

    curl_multi_close($mh); 

    return $return; 
} 

$return = curl_multi_callback($urls, function($data, $url) { 
    echo "got $url\n"; 
    return array('some stuff'); 
}, '/tmp', 30); 

//print_r($return); 
/* 
$url_dims = array(
    'url'  => 'http://www......', 
    'content' => raw content 
    'parsed' => return of get_image_dim 
) 
*/ 

只需調整你的原始功能get_image_dim消耗的原始數據,並輸出無論你正在尋找。

這是不是一個完整的功能,有可能是錯誤的,或者你需要解決的特質,但它應該作爲一個很好的起點。

更新,包括緩存。這改變了我在1秒內運行18個URL的測試,到0.007秒(使用緩存命中)。

注意:您可能不想像我一樣緩存完整的請求內容,只緩存url和解析的數據。

+0

感謝。我無法讓它與我的原始功能一起工作,但設法編輯它以獲得我可以使用的類似值。 – user2334436

+0

另一件事要注意:您可能需要考慮緩存的結果,顯著更快加載頁面(並降低帶寬使用)。我將在上面添加一個示例。 – Mike