【问题标题】:A way to make md5_file() faster?一种使 md5_file() 更快的方法?
【发布时间】:2011-02-14 13:37:42
【问题描述】:

我目前使用md5_file() 运行大约 15 个 URL 并验证它们的 MD5 哈希值。有没有办法让我更快?遍历所有这些需要很长时间。

【问题讨论】:

  • “运行大约 15 个 URL”是指类似于 md5_file('http://some.url/foo') 在一个包含 15 个不同 URL 的循环中?这些“文件”有多大?
  • 是的,就是这样。我从 MySQL 数据库中提取它们,然后在 md5_file($result) 中循环运行它们。这些文件非常小,实际上没有显示输出,没有 UI,查看时只是一个空白页
  • 问题在于您是按顺序而不是并行计算哈希值; md5_file 不是瓶颈。此外,空文件的哈希值肯定总是相同的。
  • 如果文件改变,哈希值也会改变。
  • md5_file() 本身很慢。返回 70kb 文件的 md5 需要 0.4 秒。

标签: php md5 md5-file


【解决方案1】:

您现在可能正在按顺序执行此操作。 IE。获取数据 1,处理数据 1,获取数据 2,处理数据 2,...瓶颈可能是数据传输。
你可以使用curl_multi_exec() 来并行化一点。 要么注册一个CURLOPT_WRITEFUNCTION 并处理每一块数据(这很棘手,因为 md5() 只处理一块数据)。
或者检查已经完成的 curl 句柄,然后处理该句柄的数据。

编辑:使用hash extension(提供增量哈希函数)和php5.3+ closure的快速&脏示例:

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

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

【讨论】:

  • +1。并行下载在这里可能是一个巨大的胜利。您实际上也可以并行化 md5 部分,方法是使用 md5sum CLI 命令(例如 exec('bash -c "md5sum file1 > file1.md5 &"')),或者使用 PHP 的 pcntl_fork() 之类的东西来分叉对 md5_sum() 的多个调用。这两者都有其缺点,但在适当的情况下,它们可能是最好的选择。
  • 而且我必须承认,我什至没有测试在执行回调时下载是否真的继续。但由于数据部分据说很小,我希望它没关系(很多)。
【解决方案2】:

md5 算法的速度非常快,获取 url 的速度也非常快(如果文件很大或者连接速度很慢,则速度很慢)。所以不行。你不能让它更快。

【讨论】:

    【解决方案3】:

    显然你不能用 md5_file() 做任何事情来提高速度,但是,你可以使用一些 micro-optimizations 或代码重构来获得一些速度增益,但同样你不能加速向上内置函数md5_file()

    【讨论】:

    • ...当然,一些微优化可能会减少 2 毫秒的运行时间。可能是。或者他可以并行提取 URL 并节省几秒钟。 “微优化”几乎不值得付出努力。
    • @Frank,这是在编辑问题以实际包含有问题的代码之前发布的(在添加代码之前,基本上是询问如何加速 md5_file())。
    【解决方案4】:

    没有。由于这是一个内置函数,因此无法让它更快。

    但如果您的代码在对文件进行 MD5 处理之前下载文件,则可以优化您的下载速度以加快速度。如果您提前知道文件的大小,您还可以通过在写入之前设置文件的大小(使用 ftruncate)来看到速度的小幅提升。

    另外,如果文件足够小,可以保存在内存中,并且您已经将它们保存在内存中(因为它们已被下载,或者正在为其他目的而被读取),那么您可以使用 md5 对其进行操作内存而不是md5_file,这需要再次从磁盘读取。

    【讨论】:

      【解决方案5】:

      大概您在一段时间内检查相同的 URL?你能检查一下最后修改的 URL 标头吗?如果被检查的页面没有改变,则不需要重新计算 MD5。

      您还可以异步请求页面,这样它们就可以并行处理,而不是串行处理,这样可以加快速度。

      【讨论】:

        【解决方案6】:

        MD5算法的速度是线性的。输入越大,花费的时间就越多,所以如果文件很大,你真的无能为力。

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

        【讨论】:

          【解决方案7】:

          我看到了一个非常好的优化here 的建议。这尤其适用于大文件,其中 md5_file 正在读取文件,并且此函数只是比较每个文件的第二个字节。

          【讨论】:

            【解决方案8】:

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

            这不是一种安全的方法,因为它容易出现Collision attack。您应该使用多个哈希(可能通过拆分文件)或使用其他哈希方法。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2013-09-28
              • 1970-01-01
              • 2012-04-13
              • 2021-11-15
              • 1970-01-01
              • 2021-04-24
              • 1970-01-01
              相关资源
              最近更新 更多