XML 文件上的 Regex::captures_iter 比预期慢

标签 regex rust

我的第一个 Rust 小项目涉及在大型 XML 文件上运行正则表达式:

extern crate regex;

use regex::Regex;
use std::fs::File;
use std::io::Read;

fn main() {
    let filename = "data.xml";
    let mut f = File::open(filename).expect("file not found");

    let mut contents = String::new();
    f.read_to_string(&mut contents)
        .expect("something went wrong reading the file");

    let re = Regex::new("url=\"(?P<url>.+?)\"").unwrap();
    let urls: Vec<&str> = re.captures_iter(&contents)
        .map(|c| c.name("url").unwrap().as_str())
        .collect();

    println!("{}", urls.len());
}

我确定我正在做一些非常低效的事情:

time ./target/release/hello_cargo 144408 ./target/release/hello_cargo
1.60s user
0.03s system
99% cpu
1.643 total 

99% 的 CPU 使用率都是系统占用,这似乎很不寻常。

Python 2.7 可以在不到一秒的时间内完成同样的工作:

import re 
data = open('data.xml').read()
urls = set(re.findall('url="(.+?)"', data))
print len(urls)

像这样使用 BufReader 似乎不会改变性能:

let f = File::open(filename).expect("file not found");
let mut reader = BufReader::new(f);
let mut contents = String::new();
reader
    .read_to_string(&mut contents)
    .expect("something went wrong reading the file");

如果您想在本地尝试,这是 the zipped XML file .

我在做什么事效率低下?

最佳答案

您的问题的答案是,您编写的 Rust 代码在 regex crate 的标准用法方面是最佳的。它在这里比 Python 慢一点的原因(在我的机器上慢了大约 3 倍)是因为解析捕获组在 Rust 的正则表达式箱中没有得到太多优化关注。特别是,解析捕获组需要运行较慢的内部正则表达式引擎。

在今天提到的问题中,请注意您的 Python 程序并没有做等效的工作,因为它所做的只是收集匹配项并计算它们。 Rust 程序实际上是在提取一个捕获组,这是比较麻烦的。例如,如果您改用它:

let urls: Vec<&str> = re.find_iter(&contents).map(|m| m.as_str()).collect();

然后 Rust 程序与 Python 程序执行相同的工作,并且在我的机器上快 2 倍左右。现在,公平地说,如果您修改 Python 程序以执行与原始 Rust 程序相同的工作,即,

urls = set(m.group('url') for m in re.finditer('url="(?P<url>.+?)"', data))

然后 Python 程序只会变慢一点,而原始的 Rust 程序仍然明显变慢,如上所述。

如果您不想等待 regex crate 更好地优化捕获处理,而是想让您的程序在今天运行得更快,那么您可以利用 regex 的特定功能。也就是说,避免请求捕获组并直接从匹配的文本中提取 URL。像这样:

let urls: Vec<&str> = re
    .find_iter(&contents)
    .map(|m| {
        let text = m.as_str();
        &text[5..text.len() - 1]
    })
    .collect();

这与我上面的修改一样快,比 Python 快 2 倍。不理想,但也不错。

关于XML 文件上的 Regex::captures_iter 比预期慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48777856/

相关文章:

regex - 我们如何匹配 a^n b^n?

Javascript - 正则表达式问题

rust - 如何在 Rust 中 for_each 然后对它们进行计数?

mysql - 使用 mysql crate 时无法执行 MySQL 准备语句;参数未被替换

while-loop - 在while循环中 panic ,而不是在满足条件时停止

rust - Rust 常量表达式可以使用 Default 之类的特性吗?

Python Regex 查找连字符后非数字范围的匹配组,如果范围不存在则忽略模式的其余部分

javascript - 正则表达式在所有未完成的小数前放置一个前导零 || .5 = 0.5

javascript - Preg_match 到正则表达式等效表达式以匹配任何 Unicode 字母

rust - 在以 Self 为成员的特征上实现 From