PHP卷曲-线程安全?

PHP卷曲-线程安全?,php,multithreading,curl,thread-safety,Php,Multithreading,Curl,Thread Safety,我编写了一个PHP脚本,通过libcurl检索数据并对其进行处理。它工作得很好,但出于性能原因,我将其更改为使用几十个工作线程。性能提高了50多倍,但是现在php.exe每隔几分钟就会崩溃,并且列出的故障模块是php_curl.dll。我以前有过在C中使用多线程的经验,但以前在php中根本没有使用过 我在谷歌上搜索了一下,认为cURL是线程安全的(从2001年开始): 但我找不到任何关于php_curl是否线程安全的提及 如果有必要,我将从命令行运行php。我的设置是Win7 x64、PHP5.

我编写了一个PHP脚本,通过libcurl检索数据并对其进行处理。它工作得很好,但出于性能原因,我将其更改为使用几十个工作线程。性能提高了50多倍,但是现在php.exe每隔几分钟就会崩溃,并且列出的故障模块是php_curl.dll。我以前有过在C中使用多线程的经验,但以前在php中根本没有使用过

我在谷歌上搜索了一下,认为cURL是线程安全的(从2001年开始): 但我找不到任何关于php_curl是否线程安全的提及

如果有必要,我将从命令行运行php。我的设置是Win7 x64、PHP5.5.11线程安全VC11 x86、PHP5.5线程安全VC11 x86的PHPThreads 2.0.4

下面是一些伪代码来说明我在做什么

class MyWorker extends Worker
{
    ...
    public function run()
    {
        ...
        while(1)
        {
            ...
            runCURL();
            ...
            sleep(1);
        }
    }
}

function runCURL()
{
    static $curlHandle = null;
    ...
    if(is_null($curlHandle))
    {
        $curlHandle = curl_init();
        curl_setopt($curlHandle, CURLOPT_RETURNTRANSFER, TRUE);
        curl_setopt($curlHandle, CURLOPT_USERAGENT, "My User Agent String");
    }
    curl_setopt($curlHandle, CURLOPT_URL, "The URL");
    curl_setopt($curlHandle, CURLOPT_POSTFIELDS, $data);
    curl_setopt($curlHandle, CURLOPT_HTTPHEADER, $header);
    curl_setopt($curlHandle, CURLOPT_SSL_VERIFYPEER, false);

    $result = curl_exec($curlHandle);
    ...
}

首先,
resource
类型正式不受pthreads支持;卷曲句柄是
资源
,因此不应将卷曲句柄存储在
pthreads
对象的对象范围内,因为它们可能会损坏

使之容易 pthreads提供了一种简单的方式来使用worker

在众多线程中执行的最简单方法是使用pthreads提供的内置
类:

下面的代码演示如何在几个后台线程中汇集一组请求:

<?php
define("LOG", Mutex::create());

function slog($message, $args = []) {
    $args = func_get_args();
    if (($message = array_shift($args))) {
        Mutex::lock(LOG);
        echo vsprintf("{$message}\n", $args);
        Mutex::unlock(LOG);
    }
}

class Request extends Threaded {

    public function __construct($url, $post = []) {
        $this->url = $url;
        $this->post = $post;
    }

    public function run() {
        $curl = curl_init();

        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($curl, CURLOPT_URL, $this->url);

        if ($this->post) {
            curl_setopt($curl, CURLOPT_POSTFIELDS, $this->post);
        }

        $response = curl_exec($curl);

        slog("%s returned %d bytes", $this->url, strlen($response));
    }

    public function getURL()      { return $this->url;      }
    public function getPost()     { return $this->post;     }

    protected $url;
    protected $post;
}

$max = 100;
$urls   = [];
while (count($urls) < $max) {
    $urls[] = sprintf(
        "http://www.google.co.uk/?q=%s", 
        md5(mt_rand()*count($urls)));
}

$pool = new Pool(4);

foreach ($urls as $url) {
    $pool->submit(new Request($url));
}

$pool->shutdown();

Mutex::destroy(LOG);
?>
作曲家:

{
    "require": {
        "krakjoe/promises": ">=1.0.2"
    }
}
请注意,
Request
几乎没有改变,添加的只是存放响应的地方和检测对象是否为垃圾的方法

有关池中垃圾收集的详细信息(适用于这两个示例):

slog
功能的存在只是为了使记录的输出可读

说清楚 pthreads不是新的PDO驱动程序

许多人使用
pthreads
就像使用新的PDO驱动程序一样-假设它与PHP的其余部分一样工作,并且一切都会很好

一切可能都不太好,需要研究:我们正在突破极限,在这样做的过程中,必须对pthreads的体系结构设置一些“限制”,以保持稳定性,这可能会产生一些奇怪的副作用

虽然pthreads附带了详尽的文档,其中大部分包含PHP手册中的示例,但我还不能在手册中附加以下文档

下面的文档让您了解pthreads的内部结构,每个人都应该阅读它,它是为您编写的


需要查看实际代码。。。首先,你并不真的想要一个静态句柄卷曲,你也不真的想要一个静态句柄,最有可能的是…我想你是对的,我刚刚从我获取数据的站点复制粘贴了一些API代码。在我发布这篇文章之后,我意识到了这一点,并为每个worker对象添加了一个句柄。不要将句柄存储在对象范围内,如果有多个方法需要,请将句柄保持在局部范围内卷曲。或者使用普通PHP OO抽象cURL,不要将该对象写入线程对象的对象范围,也不应该是辅助对象。你能帮我理解为什么吗?是的,现在就写答案。。。几分钟……这肯定是一个很好的答案,我没想到会有这么多,或者这么快就有答案。非常感谢乔。
{
    "require": {
        "krakjoe/promises": ">=1.0.2"
    }
}