卷曲的请求时间太长,一些错误的代码?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了卷曲的请求时间太长,一些错误的代码?相关的知识,希望对你有一定的参考价值。
我已经作出了游戏的会员,并从hiscores得到一些数据。首先,我得到的名单,然后我插入那些到我的数据库,然后我给那些卷曲得到来自hiscores的统计数据之后,我更新那些到我的数据库。
这个问题似乎是,当我做出卷曲要求我设法更新大约30名共计我的主人显示503错误之前(可能是由于最大执行时间)。但是,我必须能够更新不止于此。我说100将是最小的。
我试图优化代码,以便它可以运行一些成功得更快。看来30人左右是最大的,我可以在一个查询更新。
是不是有什么毛病代码本身它为什么这么长时间走?下面是代码的卷曲部分,这可能不是你见过的最漂亮的。我假设卷曲能够一气呵成处理方式更多的数据和我收到类似的解决方案,而数据库工作正常。可能的原因是HTTPS?以前它并不需要,但现在它是。
<?php
$ch = curl_init();
if(isset($_POST['submit'])){ //check if form was submitted
$conn = new mysqli($servername, $username, $password, $dbname);
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
//get users
$stmt = $conn->prepare("SELECT m.name, m.id, m.group_id, p.field_1, g.prefix, g.suffix FROM members m INNER JOIN pfields_content p ON m.id = p.id INNER JOIN groups g ON g.g_id = m.group_id WHERE
m.group_id = 1
");
$stmt->execute();
$result = $stmt->get_result();
while($row = mysqli_fetch_array($result, MYSQLI_ASSOC)) {
// add new member ID to database
$conn = new mysqli($servername, $username, $password, $dbname);
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
$stmt = $conn->prepare("INSERT IGNORE INTO `table` (`member_id`, `name`, `dname`) VALUES ('".$row['member_id']."', '".$row['name']."', '".$row['field_1']."')");
$stmt->execute();
// dname
if($row['field_1'] != '' || $row['field_1'] != NULL) {
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)");
curl_setopt($ch, CURLOPT_URL, "https://secure.runescape.com/m=hiscore_oldschool/index_lite.ws?player=".$row['field_1']);
curl_setopt($ch, CURLOPT_HEADER, 0);
// grab html
$data = curl_exec($ch);
$array = array();
$array = explode(',', $data);
//formula
if (!empty($array[15]) && (is_numeric($array[15]))) {
$level = ((round($array[13]/2, 0, PHP_ROUND_HALF_DOWN)+$array[9]+$array[7])/4) + (($array[3]+$array[5])*0.325);
$level = number_format($level, 2);
// if valid name, update
$conn = new mysqli($servername, $username, $password, $dbname);
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
$stmt = $conn->prepare("UPDATE table SET
member_id = '".$row['id']."',
name = '".$row['name']."',
cb = '".$level."' WHERE member_id = ".$row['id']."");
$stmt->execute();
$conn->close();
}}}}
好吧看到值得一提的几件事情:
1)为什么你只能做这么多?这里是最有可能的罪魁祸首:
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)");
curl_setopt($ch, CURLOPT_URL, "https://secure.runescape.com/m=hiscore_oldschool/index_lite.ws?player=".$row['field_1']);
curl_setopt($ch, CURLOPT_HEADER, 0);
// grab HTML
$data = curl_exec($ch);
你让一个外部卷曲呼吁每个人,这意味着你在其他网站的怜悯,需要多长时间来解决呼叫。你可以添加一些回声的周围卷曲呼叫看到每个呼叫多少时间做。但遗憾的是,你可能不会能够从您的代码获得任何更快的速度,因为你是依赖于外部进程。这可能是因为HTTPS,或者过载只是他们的系统。就像我上面说的,如果你真的想知道每走多久,添加一些回声的周围,如:
echo "About to curl runescape " . date("H:i:s");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)");
curl_setopt($ch, CURLOPT_URL, "https://secure.runescape.com/m=hiscore_oldschool/index_lite.ws?player=".$row['field_1']);
curl_setopt($ch, CURLOPT_HEADER, 0);
// grab HTML
$data = curl_exec($ch);
echo "Done with call to runescape " . date("H:i:s");
你的代码似乎并不像它的其余部分将是一个问题的速度明智的。但:
2)您的连接有点混乱。您打开一个连接,并做了查询。然后同时开始,并打开第二个连接并执行查询。然后,如果有合适的条件得到满足,你开的第三连接,并做了一些工作,然后将其关闭。原来的2个连接永远不会关闭,因为它在你的循环第二连接实际上被多次打开。你为什么不只是重新使用原来的$康恩,而不是打开每一次新的连接?
3)最后,如果你需要为你的PHP文件运行超过60秒,这样的东西添加到顶部:
set_time_limit(0);
以上要切实让脚本运行,只要你想要的。虽然,像上述的服务要好得多运行通过浏览器的CLI一个cronjob,而不是一个长期运行的脚本。
其他人似乎在做一个OK的工作搞清楚为什么代码是如此缓慢(你在做一堆卷曲的请求,而且每一个需要时间),以及其他一些问题的代码(你的缩进搞砸了,我没有挖比,对不起深刻得多)。
你怎么能解决性能问题?
这里的答案取决于一点上你的需求:你需要处理的数据发送回原来的请求,或者只是将其保存到数据库?
If you're just saving it to the database:
执行你的数据库查找你需要除了卷曲的要求做的一切,然后生成一个独立的系统进程,将尽一切卷曲请求(并保存数据到DB)异步,而你发回一个“OK,我们正在努力它”响应。
If you need to send this data back to the caller:
执行在同一时间全部卷曲的请求。 其实我不认为这是可以用PHP来完成 (见curl_multi,下文)。在其他一些语言很容易。最暴力的方法是分裂异步系统的过程对于每个卷曲的请求,并把PHP睡眠/检查循环,直到它看到所有的子进程已经写了他们的研究结果给DB。
你会遇到很多陷阱进一步为您开始使用异步的东西的工作,它不是完全清楚,你以最好的方式接近问题。也就是说,如果你走这条路,我想你会需要第一功能是exec。例如,这会催生一个独立异步的过程,会喊成虚空永远(实际上并没有做到这一点):
exec('yes > /dev/null &')
最后,我自己的计划:这是你移动你的一些执行了PHP的一个很好的机会!虽然你很可能拉断你需要的一切只是利用curl_multi,甚至有对bypassing cURL and building your own HTTP requests一些选项,我建议使用的工具更适合于手头的任务。
我通过你的代码工作,并试图重组它以这样一种方式,它更好地利用数据库连接和卷曲的请求。至于卷曲请求的目标URL通过HTTPS我修改了卷曲选项,包括证书信息,并可能会或可能不会需要进行一些其他修改 - 我也没办法全面测试此代码,所以有可能是错误的!
- 初始查询并不需要是一个
prepared statement
,因为它不使用任何用户提供的数据这样是安全的。 - 当使用
prepared statements
创建它们一次(所以不是在一个循环)和绑定占位符的变量,如果语句创建确定。在那个阶段的可变不需要实际存在(使用mysqli
时,至少 - 在PDO不同) - 只有建立一个数据库连接 - 可怜的数据库服务器试图打造这样可能遭受结果的循环新的连接。
- 当语句已运行它应该以一个新的声明可以创建进行处理。
- 如果你使用
prepared statements
之后还没有嵌入变量危及数据库(没有用户输入在这种情况下,我知道),在SQL - 使用参数的占位符!
我希望下面的帮助虽然...我可以使用随机的名字做了一些测试,不使用任何数据库调用〜6个用户5秒
<?php
try{
$start=time();
$cacert='c:/wwwroot/cacert.pem'; # <-------edit as appropriate
$baseurl='https://secure.runescape.com/m=hiscore_oldschool/index_lite.ws';
if( isset( $_POST['submit'], $servername, $username, $password, $dbname ) ){
/* should only need the one curl connection */
$curl=curl_init();
curl_setopt( $curl, CURLOPT_RETURNTRANSFER, true );
curl_setopt( $curl, CURLOPT_BINARYTRANSFER, true );
curl_setopt( $curl, CURLOPT_FOLLOWLOCATION, true );
curl_setopt( $curl, CURLOPT_USERAGENT, "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)" );
curl_setopt( $curl, CURLOPT_HEADER, false );
curl_setopt( $curl, CURLINFO_HEADER_OUT, false );
curl_setopt( $curl, CURLOPT_SSL_VERIFYPEER, true );
curl_setopt( $curl, CURLOPT_SSL_VERIFYHOST, 2 );
curl_setopt( $curl, CURLOPT_CAINFO, $cacert );
curl_setopt( $curl, CURLOPT_MAXREDIRS, 10 );
curl_setopt( $curl, CURLOPT_ENCODING, '' );
/* only need the one db connection */
$conn = new mysqli( $servername, $username, $password, $dbname );
/* initial db query does not need to be a prepared statement as there are no user supplied parameters */
$sql='select m.`name`, m.`id`, m.`group_id`, p.`field_1`, g.`prefix`, g.`suffix`
from members m
inner join pfields_content p on m.`id` = p.`id`
inner join groups g on g.`g_id` = m.`group_id`
where m.`group_id` = 1';
$res=$conn->query( $sql );
if( $res ){
/* create the prepared statement for inserts ONCE, outside the loop */
$sql='insert ignore into `table` ( `member_id`, `name`, `dname` ) values ( ?,?,? )';
$stmt=$conn->prepare( $sql );
if( $stmt ){
/* bind the placeholders to variables - the variables do not need to exist YET in mysqli */
$stmt->bind_param('iss', $id, $name, $field_1 );
/* placeholder arrays for bits of the recordset */
$data=array();
$urls=array();
/*
collect all the relevant player names into an array
and store info for use in INSERT query
*/
while( $rs=$res->fetch_object() ){
if( !empty( $rs->field_1 ) ) {
$urls[ $rs->field_1 ]=(object)array(
'name' => $rs->name,
'id' => $rs->id
);
}
$data[]=array(
'name' => $rs->name,
'id' => $rs->id, /* original code references `member_id` which does not exist in the recordset */
'field_1' => $rs->field_1
);
}
/* now loop through $data to do the inserts */
foreach( $data as $obj ){
/* create/dimension the variables for the prepared statement parameters */
$name=$obj->name;
$id=$obj->id;
$field_1=$obj->field_1;
/* run the insert cmd */
$stmt->execute();
}
/* we should now be finished with the initial prepared statement */
$stmt->free_result();
$stmt->close();
/*
now for the curl calls... no idea how many there will be but this should be known
by sizeof( $urls )
Dependant upon the number you might opt to perform the curl calls in chunks or use
`curl_multi_init` ~ more complicated but perhaps could help.
Also need to define a new sql statement ~ which sort of does not make sense as it was
~ do not need to update the `member_id`!
*/
$sql='update `table` set `name`=?, `cb`=? where `member_id`=?';
$stmt=$conn->prepare( $sql );
if( $stmt ){
$stmt->bind_以上是关于卷曲的请求时间太长,一些错误的代码?的主要内容,如果未能解决你的问题,请参考以下文章