PHP卷曲-线程安全?
我编写了一个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 下面是一些伪代码来说明我在做什么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.
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"
}
}