我一直在寻找加速基本的Python函数,基本上只需要一行文本并检查子行的行。 Python程序如下:
import time
def fun(line):
l = line.split(" ", 10)
if 'TTAGGG' in l[9]:
pass # Do nothing
line = "FCC2CCMACXX:4:1105:10758:14389# 81 chrM 1 32 10S90M = 16151 16062 CATCACGATGGATCACAGGTCTATCACCCTATTAACCACTCACGGGAGCTTTCCATGCATTTGGTATTTTCGTCTGGGGGGTGTGCACGCTTAGGGGATAGCATTG bbb^Wcbbbbccbbbcbccbba]WQG^bbcdcb_^_c_^`ccdddeeeeeffggggiiiiihiiiiihiiihihiiiihghhiihgfgfgeeeeebbb NM:i:1 AS:i:85 XS:i:65 RG:Z:1_DB31"
time0 = time.time()
for i in range(10000):
fun(line)
print time.time() - time0
我想看看我是否可以使用Rust的一些高级功能来获得一些性能,但代码运行速度要慢得多。 Rust转换是:
extern crate regex;
extern crate time;
use regex::Regex;
fn main() {
let line = "FCC2CCMACXX:4:1105:10758:14389# 81 chrM 1 32 10S90M = 16151 16062 CATCACGATGGATCACAGGTCTATCACCCTATTAACCACTCACGGGAGCTTTCCATGCATTTGGTATTTTCGTCTGGGGGGTGTGCACGCTTAGGGGATAGCATTG bbb^Wcbbbbccbbbcbccbba]WQG^bbcdcb_^_c_^`ccdddeeeeeffggggiiiiihiiiiihiiihihiiiihghhiihgfgfgeeeeebbb NM:i:1 AS:i:85 XS:i:65 RG:Z:1_DB31";
let substring: &str = "TTAGGG";
let time0: f64 = time::precise_time_s();
for _ in 0..10000 {
fun(line, substring);
}
let time1: f64 = time::precise_time_s();
let elapsed: f64 = time1 - time0;
println!("{}", elapsed);
}
fn fun(line: &str, substring: &str) {
let l: Vec<&str> = line.split(" ")
.enumerate()
.filter(|&(i, _)| i==9)
.map(|(_, e) | e)
.collect();
let re = Regex::new(substring).unwrap();
if re.is_match(&l[0]) {
// Do nothing
}
}
在我的机器上,Python时间为0.0065秒vs Rusts 1.3946s。
只需检查一些基本时序,代码的line.split()
部分大约需要1秒,正则表达式步长大约为0.4秒。这真的是对的吗,还是有正确计时的问题?
答案 0 :(得分:8)
作为基线,我用Python 2.7.6运行你的Python程序。超过10次运行,平均时间为12.2ms,标准偏差为443μs。我不知道你是如何度过 6.5ms 的好时光。
使用Rust 1.4.0-dev(febdc3b20
)运行Rust代码,没有优化,平均值为958ms,标准偏差为33ms。
使用优化(cargo run --release
)运行代码,平均值为34.6ms,标准偏差为495μs。 始终在发布模式下进行基准测试。
您可以进行进一步的优化:
在时序循环之外编译一次正则表达式:
fn main() {
// ...
let substring = "TTAGGG";
let re = Regex::new(substring).unwrap();
// ...
for _ in 0..10000 {
fun(line, &re);
}
// ...
}
fn fun(line: &str, re: &Regex) {
// ...
}
平均产生10.4ms,标准偏差为678μs。
切换到子字符串匹配:
fn fun(line: &str, substring: &str) {
// ...
if l[0].contains(substring) {
// Do nothing
}
}
平均值为8.7ms,标准差为334μs。
最后,如果你只查看一个结果而不是将所有内容都收集到一个向量中:
fn fun(line: &str, substring: &str) {
let col = line.split(" ").nth(9);
if col.map(|c| c.contains(substring)).unwrap_or(false) {
// Do nothing
}
}
平均值为6.30ms,标准差为114μs。
答案 1 :(得分:3)
Python的直接翻译将是
extern crate time;
fn fun(line: &str) {
let mut l = line.split(" ");
if l.nth(9).unwrap().contains("TTAGGG") {
// do nothing
}
}
fn main() {
let line = "FCC2CCMACXX:4:1105:10758:14389# 81 chrM 1 32 10S90M = 16151 16062 CATCACGATGGATCACAGGTCTATCACCCTATTAACCACTCACGGGAGCTTTCCATGCATTTGGTATTTTCGTCTGGGGGGTGTGCACGCTTAGGGGATAGCATTG bbb^Wcbbbbccbbbcbccbba]WQG^bbcdcb_^_c_^`ccdddeeeeeffggggiiiiihiiiiihiiihihiiiihghhiihgfgfgeeeeebbb NM:i:1 AS:i:85 XS:i:65 RG:Z:1_DB31";
let time0 = time::precise_time_s();
for _ in 0..10000 {
fun(line);
}
println!("{}", time::precise_time_s() - time0);
}
在稳定版(1.2.0)上使用cargo run --release
,与Python的0.0267
相比,我得到0.0240
(CPython,2.7.10)。鉴于Python在字符串上的in
只是一个C例程,这是合理的。
令人印象深刻的是,在测试版(1.3.0)和夜间测试版(1.4.0)上,这种情况降低到大约0.0122
,或者是CPython速度的两倍左右!