2010-08-23 4 views
2

어떤 텍스트 파일에서 발견 된 주어진 문자열 다음에 오는 첫 번째 단어 (또는 부동 소수점 숫자)를 추출하려고합니다 (How to extract the first word that follows a string? 참조). 나는 당신이 perl이나 sed, 그리고 아마도 다른 많은 방법으로 그것을 할 수 있다는 것을 압니다. 나는 성과를 찾고있다. 파싱하는 가장 빠른 방법은 무엇입니까?텍스트를 구문 분석하는 가장 빠른 방법은 무엇입니까?

+1

"성능"은 무엇입니까? 데이터의 크기는 얼마입니까? 예상되는 성능, 얼마나 많은 데이터를 추출할까요? 100MB의 결정학 데이터 출력 파일에서 많은 데이터를 추출한 사례를 기억합니다. 파일 당 추출 프로세스는 결국 약 1-2 초 (파일 읽기 포함)였습니다. –

답변

1

비슷한 질문을 할 때마다 특정 사례를 구현하고 적용 가능한 도구를 선택하여 측정합니다.

다른 요인이 그림에 왜곡되어 있음을 알 수 있습니다. 파일 열기/읽기 등의 속도 때문에 기술 권장 사항은 쓸모가 없습니다.

0

정말 단순한 경우 (실제 정규 표현식이 없다면) C가 (memchr() 및 friends)를 얻게 될 것입니다. 그렇지 않으면 TCL이 강력한 경쟁자가 될 것이고 Perl이 뒤따를 것입니다 정규 표현식 설계 기술).

추가 설명 : 설명을 다시 읽고 (관련 링크) 몇 가지 도구를 테스트하고 결과를 비교해야한다고 말하고 싶습니다. 우리에게 (어딘가에) 입력 파일을 제공하고 해당 파일을 기반으로 정확한 문제를 지정할 수 있습니까?

부록 2 (파인만에 대한) : (당신이 제안한 "사이트 디자인 /") 은이 사이트 (~ 44킬로바이트, 'sof.dat')를 저장 및 반복 검색 테스트 을 수행 펄한다. 이것은 사용되는 코드입니다 : 내 설치 (2,4GHz E6600, Win7에, ActivePerl의)와

... 
use Benchmark qw' timeit timestr '; 

{ 
    open my $fh, '<', 'sof.dat' or die $!; 
    undef $/; 
    our $data = <$fh>; 
    close $fh; 

    my $count = 100000; 
    my $t = timeit($count, ' $data =~ m|site design /| ? 1 : 0 ' ); 
    print "$count loops of code took:", timestr($t),"\n"; 
} 
... 

, 다음 타이밍 나왔다 : 코드의

100000 루프에 나섭니다 : 1 wallclock의 초 을 (1.36 usr + 0.00 sys = 1.36 CPU) @ 73746.31/s (n = 100000)

즉,이 페이지에서이 텍스트는 초당 약 74,000 번 찾을 수 있습니다. 나는 전체 파일 처리를 포함하는 경우

:

use Benchmark qw' timeit timestr '; 

{ 
    my $count = 10000; 
    my $t = timeit($count, q{ 
        open my $fh, '<', 'sof.dat' or die $!; 
        undef $/; 
        our $data = <$fh>; 
        close $fh; 
        $data =~ m|site design /| ? 1 : 0 
        }); 
    print "$count loops of code took:", timestr($t),"\n"; 
} 

을 우리는거야 : 코드의

10000 루프에 나섭니다 : 3 wallclock의 초를 (1.70 USR + 1.51 SYS = 3.21 CPU) @ 3110.42/s (n = 10000)

초당 약 3 천 건의 검색/발견 통과.

감사

RBO

+0

내 프로젝트는 초기 단계입니다. 나는 처음부터 좋은 방법을 고르고 싶었다. 이 시점에서 비정상적으로 긴 데이터 파일이 없습니다. 내가 그걸 만들 수 있다면 어떻게 붙일 수 있니? – Feynman

+0

확인 방법 :이 페이지의 html 소스 파일을 사용하십시오. 뒤에 오는 원본을 찾아 내십시오, "위치 디자인"(따옴표 없음) – Feynman

+0

@Feynman, 나는 또 다른 부록을 만들었다 –

1

하면, 디스크, 또는 더 나쁜에서 문자열을 읽어 네트워크를 읽어됩니다 대부분의 시간, 그것은 이미 어떤 제정신 방법보다 느린 크기 순서입니다 당신이 선택하는 검색. 그런데 문자열이 이미 메모리에 있고 검색 용어가 앞쪽에 있다는 것을 알고 있다면 정규 표현식 (Perl이 아닌 실제 FSM 기반 구문)이 입력 크기에 대해 시간 선형으로 작동하도록 보장됩니다. 단지 일정한 요인에 의해 더 빠를 것입니다. re2라는 빠른 정규식 엔진 라이브러리가 있습니다.

+0

내 대답보기 - "더 빠른 상수 요인"부분은 반드시 사실 일 필요는 없습니다. –

+0

맞습니다. 전체 문자열이 이미 메모리에 있으면 더 빠를 수 있습니다. 대부분의 시간을 먼저 읽어야하기 때문에 나는 그것에 대해 생각하지 않았습니다. 그리고 그것은 최선으로 선형이 될 것입니다. 음, 찾고있는 문자열이 너무 길어서 입력의 상당 부분을 건너 뛰고 읽을 수는 없지만/전혀 다운로드 할 수는 없습니다 ... –

+0

오른쪽 - 사실적으로는 별 의미가 없을 것입니다. 농도는 빠른 독서에 있어야한다. –

3

고정 된 문자열을 찾고 있다면 Boyer-Moore 또는 Boyer-Moore-Horspool과 같은 것을 사용하여 검색 할 수 있습니다 (후자의 경우 Ray Gardner의 구현을 권장합니다). B-M과 B-M-H는 모두 sublinear입니다. 대조적으로, 정규 표현식은 최상의 선형은 이며 많은 구현 (역 추적을 사용하는 구현)은 2 차입니다.

다음 단계는 가능한 빨리 데이터를 메모리로 읽는 것입니다. 현실적으로 이것은 일반적으로 병목 현상이 될 것입니다. 불행히도 병목 현상을 해결하려면 일반적으로 일부 이식 가능 코드를 사용해야합니다. 리눅스에서는 mmap이 가장 좋은 선택 인 반면, Windows에서는 인데 보통은 큰 덩어리를 한꺼번에 읽는 편이 더 좋으며 FILE_FLAG_NO_BUFFERING 플래그가있는 CreateFile입니다. 또한 I/O 완료 포트 (IOCP)를 사용하여 읽기 작업을 수행하여 검색과 읽기 작업을 동시에 수행 할 수 있습니다. 이론 상으로는 적절한 종류의 패턴을 서브 라인 방식으로 검색하는 RE 엔진을 작성할 수 있습니다. 그러나 실제로 어떤 것이 있는지는 알지 못합니다.

+0

왜'FILE_FLAG_NO_BUFFERING'을 사용해야합니까? 그렇게하면 미리 읽기가 비활성화되어 * 처리량이 저하됩니까? – Gabe

+0

미리 읽기를 비활성화하므로 IOCP (미리 읽기 헤드를 명시 적으로 제어 할 수 있음) 사용을 권장합니다. 문제는 캐싱이 미리 같은 데이터를 다시 사용할 것이라고 가정하지만,이 경우는 거의 없습니다. 동시에, 캐시에서 데이터를 플러시 할 수 있습니다. 실제로 사용되는 좋은 기회입니다. 데이터가 더러 우면 플러시를 통해 디스크에 기록해야합니다. –

관련 문제