2009-04-09 5 views
11

저는 성능이 중요하지만 중요하지 않은 프로그램을 작성하고 있습니다. 현재는 FILE*에서 줄 단위로 텍스트를 읽고 있는데 각 줄을 얻으려면 fgets을 사용합니다. 일부 성능 도구를 사용한 후에 응용 프로그램이 실행되는 시간의 20 % ~ 30 %를 발견했습니다. 내부는 fgets입니다.fgets보다 빠르게 입력 행을 읽으십니까?

텍스트 줄을 더 빨리 얻을 수있는 방법이 있습니까? 내 응용 프로그램은 다중 스레드를 사용하지 않고 단일 스레드입니다. 입력은 표준 입력 또는 파일 입력 일 수 있습니다. 미리 감사드립니다.

+0

프로그램에서 파싱하는 라인의 평균 길이 (및 가능한 표준 편차)는 얼마입니까? 이렇게하면 액세스하는 가장 빠른 방법을 결정하는 데 도움이됩니다. – Juliano

+0

@ 줄리아노 (Juliano)는 줄 길이가 항상 260 자 미만입니다. 나는 이미 회선 형성 루프를 피했다. – dreamlax

+0

입력 형식을 제어합니까? 컴팩트하게 만들 수 있습니까? – Dave

답변

7

당신이 어떤 플랫폼을 사용하고 있는지 말하지는 않지만 유닉스와 비슷한 경우 fgets() 등의 추가 버퍼링을 수행하지 않는 read() 시스템 호출을 시도 할 수 있습니다. 알. 이것은 사물의 속도를 약간 올릴 수 있지만 다른 한편으로는 사물을 천천히 늦출 수 있습니다. 알아낼 수있는 유일한 방법은 그것을 빨아서 보는 것입니다.

+0

이것은 모두의 가장 빠른 방법으로 밝혀졌습니다. 나는 결국이 길로 갔다. 그것은 "내 자신의 버퍼링"을 할 생각보다 간단했고'fgets()'를 사용하는 것보다 훨씬 빠르고 (거의 4 배) 더 빠르다는 것이 밝혀졌습니다. – dreamlax

+0

아이러니하게도, 나를 위해 pregets는 fgets보다 4 배 더 나았습니다. – abirvalg

2

데이터가 디스크에서 오는 경우 IO 경계가 될 수 있습니다.

이 경우 더 빠른 디스크를 얻으십시오 (하지만 먼저 기존 디스크를 최대한 활용하고 있는지 확인하십시오 ... 일부 Linux 배포판은 즉시 디스크 액세스를 최적화하지 않습니다 (hdparm)) 미리 데이터를 메모리에 저장 (예 : RAM 디스크에 복사)하거나 기다릴 준비를하십시오.


IO 바인딩을 사용하지 않으면 복사하는 데 많은 시간을 낭비 할 수 있습니다. 이른바 제로 카피 방식의 이점을 누릴 수 있습니다. 메모리와 같은 것이 파일을 매핑하고 포인터를 통해서만 액세스합니다.

내 전문 기술을 약간 뛰어 넘기 때문에 독서를하거나 지식이 풍부한 도움을 기다려야합니다.

BTW-- 문제가있는 것보다 더 많은 노력을 기울일 수도 있습니다. 어쩌면 더 빠른 머신은 ...

모든 문제를 해결할 NB-- 당신이 메모리 중 하나를 표준 입력을 매핑 할 수 명확하지 않다 ...

+0

때로는 디스크에서 나옵니다. 때로는 표준 입력을 통해 제공되지만, 두 경우 모두 fgets에서 보낸 시간은 거의 같습니다. 심지어 파일을위한 RAM 디스크를 만드는 것은 일을 훨씬 빠르게하지 않습니다. – dreamlax

+0

편집 후 : 문제는이 응용 프로그램이 최종 사용자의 컴퓨터에서 실행되므로 성능이 중요한 이유입니다. – dreamlax

3
당신은 당신이 읽는 보내는 시간의 양을 최소화하려고 수

방대한 양의 데이터를 RAM으로 읽어 들인 후 디스크에서 처리합니다. 디스크에서 읽기는 느리므로 전체 파일을 한 번 (이상적으로) 읽은 다음 작업하는 데 소요되는 시간을 최소화하십시오.

CPU 캐시가 실제로 RAM으로 돌아가는 시간을 최소화하는 것처럼 디스크를 실제로 사용하는 횟수를 최소화하기 위해 RAM을 사용할 수 있습니다.

+0

Stdio가 이미 버퍼링 되었습니까? 아닙니다. –

+0

나는 그렇게 생각한다. 그러나 그것이 메가 바이트보다 적다는 것을 확신한다. 그래서 그 이상을 읽는 것이 여전히 도움이된다. – GManNickG

2

환경에 따라 파일 스트림에 사용되는 내부 버퍼의 크기를 늘리려면 setvbuf()를 사용하면 성능이 향상되거나 그렇지 않을 수도 있습니다. 입력 파일 그냥 사용하여 열하면 fopen()와 BUFFER_SIZE가 (당신이 호출에 의해 할당) 버퍼의 크기가 파일에 대한 파일 *입니다

setvbuf (InputFile, NULL, _IOFBF, BUFFER_SIZE); 

-

는 구문입니다.

다양한 버퍼 크기를 사용하여 긍정적 영향을 줄 수 있습니다. 이것은 전적으로 선택 사항이며 런타임은이 호출을 통해 아무 것도 할 수 없습니다.

4
  1. 은 사용) (fgets_unlocked하지만 먼저

  2. 은() 또는 fgetc_unlocked() 대신는 fgets의()는 fgetc와 데이터를 취득하지 조심스럽게 무엇을 읽어 보시기 바랍니다.fgets()를 사용하면 파일에서 내부 버퍼 (스트림 I/O가 버퍼 됨)에서 C 런타임 라이브러리에 의해 데이터가 메모리로 두 번 복사 된 다음 해당 내부 버퍼에서 프로그램의 배열로 복사됩니다.

+0

제안에 감사하지만 Mac OS X을 사용하고 있음을 언급하는 것을 잊었습니다. fgets_unlocked는 GNU 확장이므로 사용할 수 없습니다. fgetc_unlocked를 사용해 보겠습니다. – dreamlax

+0

글쎄요, OS X은 GCC를 실행하고 있습니다. GNU 확장을 가져야합니다. 맞습니까? –

+1

@Martin : GNU 컴파일러의 확장은 아니지만 GNU C 런타임 라이브러리입니다. – dreamlax

4

전체 파일을 한 번에 버퍼로 읽습니다.

해당 버퍼의 행을 처리하십시오.

가장 빠른 해결책입니다.

0

OS가 지원하는 경우 비동기 파일 읽기를 시도 할 수 있습니다. 즉, 파일이 메모리에 읽혀지고 CPU가 다른 작업을 수행하는 중입니다. ​ ​ ​ ​ ​

start asynchronous read 
loop: 
    wait for asynchronous read to complete 
    if end of file goto exit 
    start asynchronous read 
    do stuff with data read from file 
    goto loop 
exit: 

개 이상의 CPU가 다음 하나 개의 CPU가 파일을 읽고 라인에 데이터를 구문 분석하는 경우, 다른 CPU가 각 행을 받아이를 처리 : 그래서, 코드는 같은 간다 .

0

fread()를 살펴보십시오. 그것은 나를 위해 훨씬 더 빨리, 특히 fread에 대한 버퍼가 65536으로 설정되어 있다면 더 빨리 읽습니다. 단점 : 많은 작업을해야하고 본질적으로 바이너리 읽기에서 텍스트로 변환하는 getline 함수를 작성해야합니다. 체크 아웃 : file I/O