私は、Rubyでさまざまなフォーマットの時間値を解析するテキスト変換ルーチンに取り組んでいます。 このルーチンは複雑さが増しています。私は現在、この問題に対するより良いアプローチを試しています。なぜruby scanfが遅いのですか?
私は現在、scanf
を使用する方法をテストしています。どうして?私はいつもと思ってと思っていましたが、これは正規表現より高速ですが、Rubyではどうなったのですか?それはずっと遅かった!
私は間違っていますか?
注:
require "scanf"
require 'benchmark'
def duration_in_seconds_regex(duration)
if duration =~ /^\d{2,}\:\d{2}:\d{2}$/
h, m, s = duration.split(":").map{ |n| n.to_i }
h * 3600 + m * 60 + s
end
end
def duration_in_seconds_scanf(duration)
a = duration.scanf("%d:%d:%d")
a[0] * 3600 + a[1] * 60 + a[2]
end
n = 500000
Benchmark.bm do |x|
x.report { for i in 1..n; duration_in_seconds_scanf("00:10:30"); end }
end
Benchmark.bm do |x|
x.report { for i in 1..n; duration_in_seconds_regex("00:10:30"); end }
end
これは私がscanf
最初と正規表現秒を使用して得たものです:私は、Ruby-1.9.2-P290 [x86_64版](MRI)
まずRubyのテストを使用しています:
user system total real
95.020000 0.280000 95.300000 (96.364077)
user system total real
2.820000 0.000000 2.820000 ( 2.835170)
Cを使用して第2テスト:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/types.h>
#include <string.h>
#include <regex.h>
char *regexp(char *string, char *patrn, int *begin, int *end) {
int i, w = 0, len;
char *word = NULL;
regex_t rgT;
regmatch_t match;
regcomp(&rgT, patrn, REG_EXTENDED);
if ((regexec(&rgT, string, 1, &match, 0)) == 0) {
*begin = (int) match.rm_so;
*end = (int) match.rm_eo;
len = *end - *begin;
word = malloc(len + 1);
for (i = *begin; i<*end; i++) {
word[w] = string[i];
w++;
}
word[w] = 0;
}
regfree(&rgT);
return word;
}
int main(int argc, char** argv) {
char * str = "00:01:30";
int h, m, s;
int i, b, e;
float start_time, end_time, time_elapsed;
regex_t regex;
regmatch_t * pmatch;
char msgbuf[100];
char *pch;
char *str2;
char delims[] = ":";
char *result = NULL;
start_time = (float) clock()/CLOCKS_PER_SEC;
for (i = 0; i < 500000; i++) {
if (sscanf(str, "%d:%d:%d", &h, &m, &s) == 3) {
s = h * 3600L + m * 60L + s;
}
}
end_time = (float) clock()/CLOCKS_PER_SEC;
time_elapsed = end_time - start_time;
printf("sscanf_time (500k iterations): %.4f", time_elapsed);
start_time = (float) clock()/CLOCKS_PER_SEC;
for (i = 0; i < 500000; i++) {
char * match = regexp(str, "[0-9]{2,}:[0-9]{2}:[0-9]{2}", &b, &e);
if (strcmp(match, str) == 0) {
str2 = (char*) malloc(sizeof (str));
strcpy(str2, str);
h = strtok(str2, delims);
m = strtok(NULL, delims);
s = strtok(NULL, delims);
s = h * 3600L + m * 60L + s;
}
}
end_time = (float) clock()/CLOCKS_PER_SEC;
time_elapsed = end_time - start_time;
printf("\n\nregex_time (500k iterations): %.4f", time_elapsed);
return (EXIT_SUCCESS);
}
の
Cコードの結果が明らかに高速化され、そして期待通りの正規表現の結果はscanf
結果より遅いです:
sscanf_time (500k iterations): 0.1774
regex_time (500k iterations): 3.9692
とてもRubyがあることをコメントしないでください、Cの実行時間が高速であることは明らかです解釈されて、そのようなものをしてください。
これは関連するgistです。
C言語のすべての反復式を再コンパイルしていませんか?私はRubyがそれをしないと思う。式を一度しかコンパイルしないとCの結果を見るのには興味があります。また、なぜあなたは分割を使用していますか?文字列をさらに一致させることなく、値を直接取得できるように、文字列と一致しています。 – Qtax
ええ、私は再コンパイルしている、それはそれよりもさらに高速かもしれませんが、時々エクスペットを変更する必要があります。 – AndreDurao
その後、変更されたときに再コンパイルするだけで済みます。しかし、私は数字を見たいだけです。 ;-) – Qtax