2011-03-27 56 views
2

鉴于下面的脚本以另一种语言获取单词并与服务器建立连接。如何在GET/PHP5中限制每秒连接服务器的数量?

但是,有这么多单独的字符串实体,它们中的一些实体返回为空值。 StackOverflow研究员@Pekka正确评估了Google的局限性:对结果进行定时。

Q1.如何使连接更强大/可靠,尽管速度成本高? Q230。我怎样才能有意限制每秒连接到服务器的连接数量?

只要返回的值是正确的,我愿意牺牲速度,甚至会导致120秒延迟)。现在一切都开始并在0.5秒内完成,并且翻译中存在各种空白。几乎就像荷兰奶酪(有孔),我想奶酪有一个孔,即使这意味着更长的等待时间。

正如你可以看到我自己的解决方案,脚本睡觉四分之一秒不能称为优雅...如何从这里开始?

$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); 
} 

回答

1

我怎样才能deliberatly限制连接每秒向服务器的数量?

这取决于。在一个理想的世界里,如果你期待任何级别的流量,你可能会希望你的scraper是一个守护进程,通过message or work queue进行通信。在这种情况下,守护进程将能够严格控制每秒的请求并适当地调整事情。

听起来你实际上是在用户请求上进行这种活动。说实话,你目前的睡眠策略很好。当然,这是“原油”,但它很简单,它的工作原理。如果您可能有多个用户同时提出请求,则会遇到麻烦,在这种情况下,这两个请求将无法识别另一个请求,并且每秒最多只能提供比服务允许的更多请求。

这里有几个策略。如果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个请求,则添加额外的限制。

问1.如何使连接更强大/可靠,尽管速度成本高?

如果您坚持使用谷歌翻译,您可能需要switch to the Translate v2 RESTful API。这需要一个API密钥,但注册过程将强制您通过他们的TOS,这应该记录他们的请求/期限的最大限制。由此,您可以使您的系统节流请求达到其服务支持的任何速率并保持可靠性。

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

这里是我成倍使用上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,这意味着函数将尝试总共提取8次URL,延迟时间分别为0.5,1,2,4,8,16,32和64秒(或127.5整体秒)。

至于并发进程,我建议设置一个共享内存变量与APC或类似。

希望它有帮助!