HTML kazıyıcı pcntl_fork ile verimliliği () artırma

2 Cevap php

Önceki iki sorulardan yardımıyla, ben şimdi bir veritabanına ürün bilgileri besleyen bir çalışma HTML kazıyıcı var. Ne şimdi yapmaya çalışıyorum benim kazıyıcı pcntl_fork ile çalışan alma ile beynimi etrafına sarılarak verimli geliştirmektir.

Ben, 10 ayrı parçalar halinde benim php5-cli komut bölerseniz, ben bu yüzden ben i / o veya cpu bağlı ama sadece benim kazıma fonksiyonlarının doğrusal doğası ile sınırlı değilim biliyorum büyük bir faktör ile toplam çalışma zamanını artırmak.

Birden kaynaklardan birlikte kaldırımlı ettik kodu kullanarak, ben bu çalışma test var:

<?php
libxml_use_internal_errors(true);
ini_set('max_execution_time', 0); 
ini_set('max_input_time', 0); 
set_time_limit(0);

$hrefArray = array("http://slashdot.org", "http://slashdot.org", "http://slashdot.org", "http://slashdot.org");

function doDomStuff($singleHref,$childPid) {
    $html = new DOMDocument();
    $html->loadHtmlFile($singleHref);

    $xPath = new DOMXPath($html);

    $domQuery = '//div[@id="slogan"]/h2';
    $domReturn = $xPath->query($domQuery);

    foreach($domReturn as $return) {
        $slogan = $return->nodeValue;
        echo "Child PID #" . $childPid . " says: " . $slogan . "\n";
    }
}

$pids = array();
foreach ($hrefArray as $singleHref) {
    $pid = pcntl_fork();

    if ($pid == -1) {
        die("Couldn't fork, error!");
    } elseif ($pid > 0) {
        // We are the parent
        $pids[] = $pid;
    } else {
        // We are the child
        $childPid = posix_getpid();
        doDomStuff($singleHref,$childPid);
        exit(0);
    }
}

foreach ($pids as $pid) {
    pcntl_waitpid($pid, $status);
}

// Clear the libxml buffer so it doesn't fill up
libxml_clear_errors();

Hangi aşağıdaki soruları gündeme getirmektedir:

1) Benim hrefArray Verilen 4 URL'ler içeren - dizi diyelim ki 1.000 ürün adresler içeren olsaydı bu kod 1000 çocuk süreçler doğuracağı? Eğer öyleyse, ne 10 söylemek süreçlerin miktarını sınırlamak için en iyi yoldur, ve bir örnek olarak yine 1.000 adresler, çocuk başına 100 ürün (10 x 100) çocuğun iş yükünü bölmek.

2) Ben bu pcntl_fork sürecin bir kopyasını oluşturur ve ben yapmak istiyorum ne gibi tüm değişkenler, sınıflar, kazımak için ürünlerin listesini oluşturur DOMDocument sorgu ile benim hrefArray değişkeni değiştirin, ve sonra onları besleyen öğrenmek ettik Çocuk süreçler kapalı işlem yapmak için - bu yüzden 10 çocuk işçilerin arasında yük yayılıyor.

Beynim ben (tabii ki bu işe yaramazsa, bu yüzden koşmak yok) aşağıdaki gibi bir şey yapmanız gerekir anlatıyor:

<?php
libxml_use_internal_errors(true);
ini_set('max_execution_time', 0); 
ini_set('max_input_time', 0); 
set_time_limit(0);
$maxChildWorkers = 10;

$html = new DOMDocument();
$html->loadHtmlFile('http://xxxx');
$xPath = new DOMXPath($html);

$domQuery = '//div[@id=productDetail]/a';
$domReturn = $xPath->query($domQuery);

$hrefsArray[] = $domReturn->getAttribute('href');

function doDomStuff($singleHref) {
    // Do stuff here with each product
}

// To figure out: Split href array into $maxChilderWorks # of workArray1, workArray2 ... workArray10. 
$pids = array();
foreach ($workArray(1,2,3 ... 10) as $singleHref) {
    $pid = pcntl_fork();

    if ($pid == -1) {
        die("Couldn't fork, error!");
    } elseif ($pid > 0) {
        // We are the parent
        $pids[] = $pid;
    } else {
        // We are the child
        $childPid = posix_getpid();
        doDomStuff($singleHref);
        exit(0);
    }
}


foreach ($pids as $pid) {
    pcntl_waitpid($pid, $status);
}

// Clear the libxml buffer so it doesn't fill up
libxml_clear_errors();

Ama ne anlamaya olamaz, sadece ana / ana süreçte benim hrefsArray [] inşa etmek ve çocuk süreç için onu beslemek için nasıl. Şu anda ben denedim her şeyi alt süreçlerde döngüler neden olur. Yani benim hrefsArray master inşa ve sonraki her çocuk süreç içinde alır.

Ben tüm tamamen yanlış bu konuda gidiyorum eminim, bu yüzden büyük ölçüde doğru yönde sadece genel dürtmek seviniriz.

2 Cevap

Ben her gün bu önermek gibi görünüyor, ama Gearman baktım? Orada bile bir iyi belgelenmiş PECL class.

Gearman bir iş kuyruk sistemidir. Bağlayabilir ve işler için dinlemek işçileri, bağlamak ve işlerini göndermek müşteri yaratmak istiyorum. İstemci ya tamamlanması istenen iş için bekleyebilir, ya da onu ateş ve unutabilirsiniz. Seçiminize göre, işçiler bile onlar sürecinde durum güncellemeleri, ve ne kadar geri gönderebilirsiniz.

Başka bir deyişle, süreçleri ve iş parçacığı hakkında endişelenmenize gerek kalmadan, çoklu süreçleri veya parçacığı faydaları olsun. Müşteriler ve çalışanlar hatta farklı makinelerde olabilir.

Introduction

O Message Queue Charles Hala önerdi ama olan kullanmak iyi bir fikir olabilir iken pcntl_fork() HTML scraper performansını artırmak için tek yol değildir Lütfen workers bu isteği çekmek için hızlı etkili bir yol gerekir

Solution 1

curl_multi_init ... kıvırmak aslında daha hızlı ve çok kıvırmak kullanarak size paralel işleme verir kullanın

PHP DOC Gönderen

curl_multi_init çoklu cURL işleme paralel kolları verir.

Yani Onun yerine sadece kullanabileceğiniz dosyaları birkaç kez yüklemek için $html->loadHtmlFile('http://xxxx'); kullanarak curl_multi_init, aynı anda birden fazla url yüklemek için

İşte bazı ilginç Uygulamaları vardır

Solution 2

Sen pthreads PHP multi-diş kullanmak için kullanabilirsiniz

Örnek

// Number of threads you want
$threads = 10;

// Treads storage
$ts = array();

// Your list of URLS // range just for demo
$urls = range(1, 50);

// Group Urls
$urlsGroup = array_chunk($urls, floor(count($urls) / $threads));

printf("%s:PROCESS  #load\n", date("g:i:s"));

$name = range("A", "Z");
$i = 0;
foreach ( $urlsGroup as $group ) {
    $ts[] = new AsyncScraper($group, $name[$i ++]);
}

printf("%s:PROCESS  #join\n", date("g:i:s"));

// wait for all Threads to complete
foreach ( $ts as $t ) {
    $t->join();
}

printf("%s:PROCESS  #finish\n", date("g:i:s"));

Çıktı

9:18:00:PROCESS  #load
9:18:00:START  #5592     A
9:18:00:START  #9620     B
9:18:00:START  #11684    C
9:18:00:START  #11156    D
9:18:00:START  #11216    E
9:18:00:START  #11568    F
9:18:00:START  #2920     G
9:18:00:START  #10296    H
9:18:00:START  #11696    I
9:18:00:PROCESS  #join
9:18:00:START  #6692     J
9:18:01:END  #9620       B
9:18:01:END  #11216      E
9:18:01:END  #10296      H
9:18:02:END  #2920       G
9:18:02:END  #11696      I
9:18:04:END  #5592       A
9:18:04:END  #11568      F
9:18:04:END  #6692       J
9:18:05:END  #11684      C
9:18:05:END  #11156      D
9:18:05:PROCESS  #finish

Ikinci

class AsyncScraper extends Thread {

    public function __construct(array $urls, $name) {
        $this->urls = $urls;
        $this->name = $name;
        $this->start();
    }

    public function run() {
        printf("%s:START  #%lu \t %s \n", date("g:i:s"), $this->getThreadId(), $this->name);
        if ($this->urls) {
            // Load with CURL
            // Parse with DOM
            // Do some work

            sleep(mt_rand(1, 5));
        }
        printf("%s:END  #%lu \t %s \n", date("g:i:s"), $this->getThreadId(), $this->name);
    }
}