如何让md5_file()函数更快?

11

我目前使用md5_file()来验证约15个URL的MD5哈希值。有没有一种方法可以使这个过程更快?运行所有URL需要太长时间了。


“run through about 15 URLs” 的意思是在循环中使用 md5_file('http://some.url/foo') 等函数来处理 15 个不同的 URL?这些“文件”有多大? - VolkerK
是的,就是这样。我从MySQL数据库中提取它们,然后在循环中运行md5_file($result)。这些文件非常小,实际上没有显示输出,没有UI,只有一个空白的白色页面。 - Rob
问题在于你是按顺序而不是并行计算哈希值;md5_file 不是瓶颈。此外,空文件的哈希值肯定是相同的。 - salathe
如果文件发生更改,哈希值也会发生变化。 - Rob
md5_file()本身很慢。对于一个70kb的文件,它需要0.4秒才能返回其md5值。 - Elzo Valugi
8个回答

15

可能你目前是按顺序执行。即获取数据1,处理数据1,获取数据2,处理数据2...这样数据传输可能会成为瓶颈。
你可以使用curl_multi_exec()来进行并行处理。 可以注册一个CURLOPT_WRITEFUNCTION并处理每个数据块(这有些棘手,因为md5()仅适用于精确的一个数据块)
或者检查已经完成的curl句柄,然后处理该句柄的数据。

编辑:快速且简单的示例使用哈希扩展(提供了增量哈希函数)和php5.3+闭包

$urls = array(
  'http://stackoverflow.com/',
  'http://sstatic.net/so/img/logo.png',
  'http://www.gravatar.com/avatar/212151980ba7123c314251b185608b1d?s=128&d=identicon&r=PG',
  'http://de.php.net/images/php.gif'
);

$data = array();
$fnWrite = function($ch, $chunk) use(&$data) {
  foreach( $data as $d ) {
    if ( $ch===$d['curlrc'] ) {
      hash_update($d['hashrc'], $chunk);
    }
  }
};

$mh = curl_multi_init();
foreach($urls as $u) {
  $current = curl_init();
  curl_setopt($current, CURLOPT_URL, $u);
  curl_setopt($current, CURLOPT_RETURNTRANSFER, 0);
  curl_setopt($current, CURLOPT_HEADER, 0);
  curl_setopt($current, CURLOPT_WRITEFUNCTION, $fnWrite);
  curl_multi_add_handle($mh, $current);
  $hash = hash_init('md5');
  $data[] = array('url'=>$u, 'curlrc'=>$current, 'hashrc'=>$hash); 
}

$active = null;
//execute the handles
do {
  $mrc = curl_multi_exec($mh, $active);
} while ($mrc == CURLM_CALL_MULTI_PERFORM);

while ($active && $mrc == CURLM_OK) {
  if (curl_multi_select($mh) != -1) {
    do {
      $mrc = curl_multi_exec($mh, $active);
    } while ($mrc == CURLM_CALL_MULTI_PERFORM);
  }
}

foreach($data as $d) {
  curl_multi_remove_handle($mh, $d['curlrc']);
  echo $d['url'], ': ', hash_final($d['hashrc'], false), "\n";
}
curl_multi_close($mh);

(虽然我还没有检查结果...但这只是一个起点)


2
+1. 在这里并行下载很可能是一个巨大的优势。您实际上也可以通过使用md5sum CLI命令(例如exec('bash -c "md5sum file1 > file1.md5 &"'))或使用类似PHP的pcntl_fork()来分叉多个调用md5_sum()来并行化md5部分。它们都有缺点,但在正确的上下文中,它们可能是最好的选择。 - Frank Farmer
我必须承认,我甚至没有测试下载是否在执行回调时继续。但由于数据部分应该很小,我希望这不会太重要。 - VolkerK

0

MD5算法已经非常快了,获取URL也已经尽可能地快(如果文件很大或者你的连接速度慢,则会变慢)。所以答案是否定的。你无法让它更快。


0

显然,您无法通过 md5_file() 做任何使其更快的操作。但是,您可以使用一些微优化或代码重构来获得一些速度提升,但您仍无法加速内置函数md5_file()


1
当然,一些微小的优化可能会将运行时间缩短2毫秒。也许。或者他可以并行拉取URL并节省几秒钟的时间。 "微小的优化" 几乎不值得花费这样的努力。 - Frank Farmer
@Frank,这篇文章是在问题被编辑之前发布的,实际上并没有包含相关代码(在添加代码之前,基本上是在询问如何加速md5_file()函数)。 - Tim Post

0

不行。由于这是一个内置函数,无法加快其速度。

但是,如果您的代码在进行MD5计算之前下载文件,可能可以优化下载速度。如果您事先知道文件的大小,可以在写入文件之前设置文件的大小(使用ftruncate),这样可能会略微提高速度。

此外,如果文件足够小以适应内存,并且您已经将它们保存在内存中(因为它们已被下载或正在被用于其他目的),那么您可以使用md5在内存中操作它,而不是使用需要从磁盘重新读取的md5_file


0

假设您在一段时间内检查相同的URL?您可以检查URL的最后修改标头吗?如果正在检查的页面没有更改,则无需重新计算MD5。

您还可以异步请求页面,以便可以并行处理而不是串行处理,这应该可以加快速度。


0

MD5算法的速度是线性的。输入越大,花费的时间就越多,所以如果文件很大,你真的没有太多可以做的。

现在,正如VolkerK已经建议的那样,问题很可能不是MD5哈希,而是通过网络检索和读取文件。


0

我看到了一个非常好的优化建议这里。这对于大文件特别有效,因为md5_file正在读取文件,而此函数仅比较每个文件的第二个字节。


-1

解释你想要做什么会有所帮助。如果你想要使用MD5哈希值验证文件:

这不是一种安全的方法,因为它容易受到碰撞攻击的影响。你应该使用多个哈希值(也许通过分割文件)或者使用其他哈希方法。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接