给定下面的脚本,该脚本以另一种语言提取单词并与服务器建立连接。
但是,有很多单独的字符串实体,其中一些返回为空值。 StackOverflow的研究员@Pekka正确评估了Google的局限性:定时结果。
问:如何以速度为代价,如何使连接更加强大/可靠?
的 Q2。如何逐步限制每秒与服务器建立的连接数量?
只要返回的值正确,我愿意牺牲速度,即使它会导致120秒的延迟。现在一切都在0.5秒内开始并完成,翻译中存在各种差距。几乎像荷兰奶酪(带孔),我想要奶酪没有孔,即使这意味着更长的等待时间。
正如你所看到的那样,我自己将脚本置于睡眠状态1/4秒的解决方案不能称为优雅...如何从这里开始?
$url='http://ajax.googleapis.com/ajax/services/language/translate?v=1.0&q=' . rawurlencode($string) . '&langpair=' . rawurlencode($from.'|'.$to);
$response = file_get_contents($url,
null,
stream_context_create(
array(
'http'=>array(
'method'=>"GET",
'header'=>"Referer: http://test.com/\r\n"
)
)
));
usleep(250000); # means 1/4 of second deliberate pauze
return self::cleanText($response);
}
答案 0 :(得分:1)
你可以从较低的等待时间开始,只有在你没有得到回应时才增加它。这样的事情。
$delay = 0;
$i = 0;
$nStrings = count($strings);
while ($i < $nStrings) {
$response = $this->getTranslation($strings[$i]);
if ($response) {
$i++;
# save the response somewhere
else {
$delay += 1000;
usleep($delay);
}
}
答案 1 :(得分:1)
如何逐步限制每秒与服务器建立的连接数量?
这取决于。在理想的世界中,如果您期望任何级别的流量,您可能希望您的刮刀成为通过message or work queue与之通信的守护进程。在这种情况下,守护进程将能够严格控制每秒的请求并适当地限制事情。
听起来你实际上是根据用户请求进行直播。说实话,你目前的睡眠策略很好。当然,它是“粗糙”,但它很简单并且有效。当您可能有多个用户同时发出请求时会出现问题,在这种情况下,这两个请求将不知道另一个请求,并且每秒最终会有比服务允许的更多请求。< / p>
这里有一些策略。如果URL永远不会更改,即您只限制单个服务,则基本上需要semaphore来协调多个脚本。
考虑使用简单的锁定文件。或者,更确切地说,锁定文件上的文件锁定:
// Open our lock file for reading and writing;
// create it if it doesn't exist,
// don't truncate,
// don't relocate the file pointer.
$fh = fopen('./lock.file', 'c+');
foreach($list_of_requests as $request_or_whatever) {
// At the top of the loop, establish the lock.
$ok = flock($fh, LOCK_EX):
if(!$ok) {
echo "Wow, the lock failed, that shouldn't ever happen.";
break; // Exit the loop.
}
// Insert the actual request *and* sleep code here.
$foo->getTranslation(...);
// Once the request is made and we've slept, release the lock
// to allow another process that might be waiting for the lock
// to grab it and run.
flock($fh, LOCK_UN);
}
fclose($fh);
这在大多数情况下都能正常使用。如果您使用的是超低成本或低质量的共享主机,由于底层文件系统(不能)的工作方式,锁可能会适得其反。 flock
is also a bit finicky on Windows
如果您要处理多项服务,事情会变得更加棘手。我的第一直觉是在数据库中创建一个表,并开始跟踪每个请求,如果在过去的Z秒内对域Y进行了多次X请求,则添加额外的限制。
Q1。如何以速度为代价,如何使连接更加强大/可靠?
如果您坚持使用Google翻译,则可能需要switch to the Translate v2 RESTful API。这需要一个API密钥,但注册过程将强制您通过他们的服务条款,这应该记录他们的请求/期间最大限制。通过这种方式,您可以将系统限制请求到他们的服务支持的任何速率,并保持可靠性。
答案 2 :(得分:1)
以下是我在my CURL wrapper上使用的代码片段,延迟呈指数增长 - 这是一件好事,否则您可能最终只是强调服务器并且永远不会得到积极响应:
function CURL($url)
{
$result = false;
if (extension_loaded('curl'))
{
$curl = curl_init($url);
if (is_resource($curl))
{
curl_setopt($curl, CURLOPT_FAILONERROR, true);
curl_setopt($curl, CURLOPT_AUTOREFERER, true);
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
for ($i = 1; $i <= 8; ++$i)
{
$result = curl_exec($curl);
if (($i == 8) || ($result !== false))
{
break;
}
usleep(pow(2, $i - 2) * 1000000);
}
curl_close($curl);
}
}
return $result;
}
这里的$ i变量的最大值为8,这意味着该函数将尝试总共获取URL 8次,相应的延迟分别为0.5,1,2,4,8,16,32和64秒(或总计127.5秒)。
对于并发进程,我建议使用APC或类似设置共享内存变量。
希望它有所帮助!