pthreads会破坏数组结果

时间:2017-08-30 19:19:02

标签: php pthreads

我有一个使用pthreads v3.1.6和PHP 7.0.22的代码。我遇到的问题是线程不返回数组值。我的代码如下

$threadCount = 1;

$url_idList = range(1,2000);
$url_idListChunked = array_chunk($url_idList, $threadCount);

class WorkerThreads extends Thread {
    private $threadName, $url_id;

    public function __construct($threadName,$url_id) {
        $this->threadName = $threadName;
        $this->url_id = $url_id;
        $this->result = [];
    }

    public function run() {
        if ($this->threadName && $this->url_id) {
            printf('%sLoading URL #: %s' . "\n", $this->threadName, $this->url_id);
            $this->result = send_request('GET',$this->url_id,NULL,$this->threadName);
        }
    }
}

while(count($url_idListChunked)){
    $url_idListChunk = array_shift($url_idListChunked);
    $workers = [];
    foreach (range(0,count($url_idListChunk)-1) as $i) {
        $threadName = "Thread #".$i.": ";
        $workers[$i] = new WorkerThreads($threadName,$url_idListChunk[$i]);
        $workers[$i]->start();
    }

    foreach (range(0,count($url_idListChunk)-1) as $i) {
        $workers[$i]->join();
        print_r($workers[$i]);
        exit();
        echo $workers[$i]['threadName']."Result for URL #: ".$workers[$i]['url_id']."\n";
    }

}

function send_request($method,$url_id,$data,$threadName=NULL){

    $url = 'https://www.example.tld/?id='.$url_id;

    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_HEADER, TRUE);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
    curl_setopt($ch, CURLOPT_TIMEOUT, 3);
    if(!$data && $method=='POST'){
        $data = generate_post_data();
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
    }
    $response = curl_exec($ch);
    while((curl_errno($ch) == 6 OR curl_errno($ch) == 28)){
        $response = curl_exec($ch);
        echo $threadName.'Curl error #'.curl_errno($ch).' - ' . curl_error($ch)." Retrying.\n";
        sleep(2);       
    }

    curl_close($ch);

    $result['data'] = $response;

    return $result;

}

当我尝试print_t($workers)时,收到以下错误消息Uncaught RuntimeException: pthreads detected an attempt to connect to an object which has already been destroyed。为什么我会丢失数组结果?似乎线程没有问题将字符串传回去。

1 个答案:

答案 0 :(得分:0)

嗨,我不完全确定使用start-> join方法是你想要实现的首选方法吗?我认为你需要使用在pthreads中制作的pool collectable方法。

如果您想从分块批次中收集结果,这个示例可能会激发您的工作。我个人使用它,这是将pthreads推向极限的最快方法。小心不要将池号推送到CPU线程上(在本例中它是10个内核)。

如果我可以说你的代码,不要试图从pthreads工作者输出屏幕上的东西,它肯定会搞乱。返回对象并在集合上回显它。确保您的类中的结果已公开以允许返回的对象。

更不用说多卷曲可能是最快和最合适的方式。

/* pthreads batches */
$batches = array();

$nbpool = 20; // cpu 10 cores 

/* job 1 */
$list = [/* data1 */];
$url_idList[] = array_chunk($list, 5000);

/* job 2 */
$list2 = [/* data2 */];
$url_idList[] = array_chunk($list, 10000);

/* final collected results */
$resultFinal = [];

/* loop across batches */
foreach ($url_idList as $key => $url_idListChunked) {

    $url_idListChunk = array_shift($url_idListChunked);

    /* for intermediate collection */
    $data[$key] = [];

    /* how many workers */
    $workCount = count($url_idListChunk);

    /* set pool job up to max cpu capabilities */
    $pool = new Pool($nbpool, Worker::class);

    /* pool cycling submit */
    foreach (range(1, $workCount) as $i) {
        $chunck = $url_idListChunk[$i - 1];
        $pool->submit(new WorkerThreads(($i - 1), $chunck));
    }

    /* on collection cycling */
    $collector = function (\Collectable $work) use (&$data) {

        /* is worker complete ? */
        $isGarbage = $work->isGarbage();

        /* worker complete */
        if ($isGarbage) {
            $result = $work->result;
            $info = $work->info;
            $data[$key] = $result;

            /* echo result info outside worker */
            echo($info);
        }
        return $isGarbage;
    };
    do {
        /* collection on pool stack */
        $count = $pool->collect($collector);
        $isComplete = count($data) === $workCount;
    } while (!$isComplete);

    /* push stack results */
    array_push($resultFinal, $data);

    /* close pool */
    $pool->shutdown();
}

class WorkerThreads extends \Threaded implements \Collectable {

    private $url_id;
    private $isGarbage;
    private $threadName;
    public $result;
    public $info;

    public function __construct($i, $url_id) {
        $this->threadName = "Thread #" . $i . ": ";
        $this->url_id = $url_id;
    }

    public function run() {
        if ($this->threadName && $this->url_id) {
            $this->result = send_request('GET', $this->url_id, NULL, $this->threadName);
        }
        $this->info = $this->threadName . " Result for URL #: " . $this->url_id;
        $this->isGarbage = true; // yeah, it s done
    }

    public function isGarbage(): bool {
        return $this->isGarbage;
    }

}