- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我编写了一个 PHP 脚本,它通过 libcurl 检索数据并对其进行处理。它工作正常,但出于性能原因,我将其更改为使用数十个工作线程(线程)。性能提高了 50 多倍,但是现在 php.exe 每隔几分钟就会崩溃,列出的错误模块是 php_curl.dll。我之前确实有过 C 语言的多线程经验,但之前在 php 中根本没有使用过它。
我用谷歌搜索了一下,据说 cURL 是线程安全的(截至 2001 年): http://curl.haxx.se/mail/lib-2001-01/0001.html但是我找不到任何关于 php_curl 是否线程安全的提及。
以防万一,我从命令行运行 php。我的设置是 Win7 x64、PHP 5.5.11 线程安全 VC11 x86、适用于 PHP 5.5 线程安全 VC11 x86 的 PHP pthreads 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);
...
}
最佳答案
首先,pthreads 官方不支持resource
类型; curl 句柄是一个资源
,因此您不应将 curl 句柄存储在 pthreads
对象的对象范围内,因为它们可能会损坏。
pthreads 提供了一种使用 worker 的简单方法...
在多个线程之间执行的最简单方法是使用 pthreads 提供的内置 Pool
类:
下面的代码演示了如何在几个后台线程中合并一堆请求:
<?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);
?>
您的特定任务要求您现在处理数据,您可以将此功能写入上述设计中......或者
promises 是一种 super 奇特的并发形式......
Promise 适合此处任务的性质:
以下代码显示了如何使用pthreads/promises
发出相同的请求并处理响应:
<?php
namespace {
require_once("vendor/autoload.php");
use pthreads\PromiseManager;
use pthreads\Promise;
use pthreads\Promisable;
use pthreads\Thenable;
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);
}
}
/* will be used by everything to report errors when they occur */
trait ErrorManager {
public function onError(Promisable $promised) {
slog("Oh noes: %s\n", (string) $promised->getError());
}
}
class Request extends Promisable {
use ErrorManager;
public function __construct($url, $post = []) {
$this->url = $url;
$this->post = $post;
$this->done = false;
}
public function onFulfill() {
$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);
}
$this->response = curl_exec($curl);
}
public function getURL() { return $this->url; }
public function getPost() { return $this->post; }
public function getResponse() { return $this->response; }
public function setGarbage() { $this->garbage = true; }
public function isGarbage() { return $this->garbage; }
protected $url;
protected $post;
protected $response;
protected $garbage;
}
class Process extends Thenable {
use ErrorManager;
public function onFulfilled(Promisable $request) {
slog("%s returned %d bytes\n",
$request->getURL(), strlen($request->getResponse()));
}
}
/* some dummy urls */
$max = 100;
$urls = [];
while (count($urls) < $max) {
$urls[] = sprintf(
"http://www.google.co.uk/?q=%s",
md5(mt_rand()*count($urls)));
}
/* initialize manager for promises */
$manager = new PromiseManager(4);
/* create promises to make and process requests */
while (@++$id < $max) {
$promise = new Promise($manager, new Request($urls[$id], []));
$promise->then(
new Process($promise));
}
/* force the manager to shutdown (fulfilling all promises first) */
$manager->shutdown();
/* destroy mutex */
Mutex::destroy(LOG);
}
?>
Composer :
{
"require": {
"krakjoe/promises": ">=1.0.2"
}
}
请注意,Request
几乎没有变化,添加的只是保存响应的地方以及检测对象是否为垃圾的方法。
有关从池中收集垃圾的详细信息,这适用于两个示例:
slog
函数的存在只是为了使记录的输出可读
pthreads 不是新的 PDO 驱动程序......
许多人使用 pthreads
就像他们使用新的 PDO 驱动程序一样 - 假设它像 PHP 的其余部分一样工作并且一切都会很好。
一切可能都不是很好,需要研究:我们正在挑战极限,在这样做的过程中,必须对 pthreads 的体系结构施加一些“限制”以保持稳定性,这可能会有一些奇怪的副作用。
虽然 pthreads 附带详尽的文档,其中大部分包括 PHP 手册中的示例,但我无法在手册中附加以下文档。
以下文档让您了解 pthreads 的内部结构,每个人都应该阅读它,它是为您编写的。
关于PHP cURL - 线程安全吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23319866/
我以前从未做过任何 curl ,所以需要一些帮助。我试图从示例中解决这个问题,但无法理解它! 我有一个 curl 命令,我可以从 Windows 命令行成功运行该命令,该命令行在 Solr 中索引 p
curl -v有什么区别和 curl -I ? 我可以看到 -v是冗长的和 -I是标题。有什么具体的吗? 最佳答案 -I (大写字母 i)在 curl 中表示“没有正文”,对于 HTTP 表示发送 H
我正在使用curl php API访问FTP链接。在特定站点上,它给出错误代码9(拒绝访问)。但是,可以从IE和Firefox访问该链接。 然后,我运行curl命令行,它给出了相同的“访问拒绝”结果。
我已经使用curl有一段时间了,它可以正常工作,但是使用使用用户'domain\username'来验证curl的代理时,无法请求授权。授权方法是NTLM。此代码放入批处理文件中。 代码: curl
“curl”默认使用哪些证书? 例子: curl -I -L https://cruises.webjet.com.au 在 Ubuntu 15.04 上失败 curl: (60) SSL certi
我知道终端输出的一部分是请求的持续时间,剩余时间等。但是是否有一些文档指定了curl命令的终端输出的每一列到底是什么?手册页上的内容非常稀疏。 最佳答案 可能不容易找到,但已在the curl boo
我想通过 curl 在我自己的云服务器上的特定文件夹中上传文件。例如:http://www.myowncloudserver.com/remote.php/webdav/{MY_FOLDER}。此时我
我的网站上有一个密码保护的Web文件夹,我正在使用Curl在另一个域上获取该文件夹,我想要的是:当我尝试打开URL时,应该问我用户名和密码,而不是让它显示“需要授权”。 例: http://www.e
有没有一种方法可以通过简单的Curl获取Rabbitmq中队列的大小(剩余消息)? 类似于curl -xget http://host:1234/api/queue/test/stats 谢谢 最佳答
关闭。这个问题是opinion-based .它目前不接受答案。 2年前关闭。 锁定。这个问题及其答案是locked因为这个问题是题外话,但具有历史意义。它目前不接受新的答案或互动。 我最近开始在我的
我想访问需要用户名/密码的 URL。我想尝试用curl 访问它。现在我正在做类似的事情: curl http://api.somesite.com/test/blah?something=123 我收
我正在尝试使用 CURL 进行查询ElasticSearch 中的命令在windows平台。 例如:localhost:9200/playground/equipment/1?pretty 我收到一条
我正在尝试使用 Docker 构建和运行 Marklogic 实例。 Marklogic 提供了一些不错的 http api,所以,作为最终 CMD在 Dockerfile 中,我运行两个脚本,它们通
我正在尝试通过 cURL 检索网页的内容(比方说 http://www.foo.com/bar.php )。 当我在浏览器中加载网站时,加载页面时会出现动画,页面最终会显示出来。 但是使用 cURL,
我正在尝试使用带代理的命令行 CURL 获取响应状态代码。 这会返回整个页面,但我只想要状态代码。我怎么做?谢谢。 curl -sL -w -x IP:PORT "%{http_code}\n""ht
我有一段代码检查 http/s 端点的状态和加载时间。然后我会为每个顶级页面检查 1 级 href,以检查页面引用的所有内容是否也加载了 200。 (我查了50个顶级页面,每个顶级页面平均有8个链接)
curl --upload-file 和 curl --form file=@/path/file 有什么区别?这些 HTTP 请求有何不同? 最佳答案 --上传文件 (使用 HTTP 或 HTTPS
我正在尝试使用 system-curl 安装 cmake,使用 ./bootstrap --system-curl,如 here 所示.这样做,我得到了: -- Could NOT find
我需要使用 Curl 下载 Youtube 视频的特定部分。 (假设我想下载前 2MB)我在 Curl 中使用 -r 开关来实现这一点。它适用于非 YouTube 链接,但 Youtube 链接会忽略
我希望在使用 curl 命令从远程服务器下载文件后,将时间戳或日期添加到文件名中。我知道您可以使用 -o 来指定您要为文件命名的内容。我看到过这样的建议:-o "somefile $(date +\"
我是一名优秀的程序员,十分优秀!