2010-08-18 7 views
6

수천 개의 원본 비디오 프레임을 순차적으로 읽고 처리하는 매우 큰 이진 파일 집합이 있는데, CPU 사용률이 더 높은 것으로 보이는대로 최적화하려고합니다. I/O 바인딩보다.NET 이진 파일 읽기 성능

프레임이 현재이 방식으로 읽고, 나는 이것이 가장 큰 원인 인 것으로 생각되고있다 :

private byte[] frameBuf; 
BinaryReader binRead = new BinaryReader(FS); 

// Initialize a new buffer of sizeof(frame) 
frameBuf = new byte[VARIABLE_BUFFER_SIZE]; 
//Read sizeof(frame) bytes from the file 
frameBuf = binRead.ReadBytes(VARIABLE_BUFFER_SIZE); 

그것을 방지하기 위해 I/O를 다시 구성 할 .NET에서 큰 차이를 만들 것 각 프레임마다 이러한 새로운 바이트 배열을 모두 생성합니까?

순수한 C/C++ 배경에서 왔기 때문에 .NET의 메모리 할당 메커니즘에 대한 이해가 약합니다. 내 생각은 프레임의 실제 크기를 추적하는 정수가 포함 된 매우 큰 공유 버퍼를 포함하는 정적 버퍼 클래스를 공유하기 위해 이것을 다시 작성하는 것이지만 현재 구현의 단순성과 가독성을 좋아하며 CLR은 이미 알고있는 어떤 방법으로 이것을 처리합니다.

모든 입력 사항을 보내 주시면 감사하겠습니다.

+5

다른 소스에서 얻은 성능 저하를 방지하기 위해 프로필러를 실행 했습니까? 아니면 그냥 가서 "아마 그럴거야"라고 생각 했습니까? –

+0

안녕 David, 성능 프로파일 러를 몇 번 실행했는데이 특정 방법이 가장 비싼 방법입니다. 따라서이 "새로운 byte []"메서드가 .NET에서 확실한 성능 킬러인지 확인하려고합니다. C 프로그래머로서, 이것은 각 버퍼에 대한 수천 개의 "malloc"문장과 비슷하게 보이는데, 이는 재사용 된 버퍼보다 ​​확실히 느릴 것입니다. – rnd

답변

7

binRead.ReadBytes을 사용하는 경우 frameBuf을 초기화 할 필요가 없습니다. 방금 작성한 바이트 배열을 덮어 쓸 새 바이트 배열이 다시 나타납니다. 이것은 각 읽기에 대해 새로운 배열을 생성합니다.

바이트 배열을 많이 만들지 않으려면 binRead.Read을 사용하면 바이트를 배열에 넣을 수 있습니다. 하지만 다른 스레드가 배열을 사용하고 있다면 배열의 내용이 바로 앞에 표시되는 것을 볼 수 있습니다. 버퍼를 재사용하기 전에 버퍼가 완료되었다는 것을 보장 할 수 있어야합니다.

+0

지적 해 주셔서 고마워요. 중복 된 할당이 상당히 느려지고 있다고 확신합니다.그리고 정적 공유 배열은 정확히 내가 생각하고있는 것입니다. 그러나 성능 향상이 바이트 배열을 만드는 것에 비해 크지 않다면, 당신이 윤곽을 그리는 매우 유사한 합병증 (공유 액세스)에 대해 우아한 해결책을 고집하는 편이 낫습니다. . – rnd

1

여기에서주의해야합니다. 이와 같은 코드에서 완전히 위조 된 테스트 결과를 얻는 것은 매우 쉽습니다. 실제 사용에서는 결코 재현 할 수없는 결과입니다. 문제는 파일 시스템 캐시이며 파일에서 읽은 데이터를 캐시합니다. 문제는 반복해서 테스트를 실행하고 코드를 수정하고 개선 사항을 찾는 것으로 시작됩니다.

테스트를 실행 한 두 번째 이후의 데이터는 더 이상 디스크에서 분리되지 않습니다. 캐시에 여전히 존재하며, 프로그램으로 가져 오기 위해 메모리 대 메모리 복사본 만 필요합니다. 이는 매우 빠르며, 마이크로 초 또는 오버 헤드와 복사에 필요한 시간을 더한 것입니다. 현대식 컴퓨터에서 초당 5 기가 바이트 이상의 버스 속도로 실행됩니다.

테스트를 통해 버퍼를 할당하고 데이터를 읽는 데 소요되는 시간에 비례하여 많은 시간을 소비하게됩니다.

실제 사용에서는 드물게 재 작성됩니다. 데이터가 캐시에 저장되지는 ​​않습니다. 이제는 슬러지 디스크 드라이브가 데이터를 검색해야하므로 (수 밀리 초) 디스크 플래터에서 읽을 필요가 있습니다 (기껏해야 초당 수십 메가 바이트). 데이터를 읽는 데는 시간이 오래 걸리는 네 가지 중 큰 세 가지가 필요합니다. 처리 속도를 두 배 빠르게 할 수 있었다면 프로그램은 실제로는 0.05 % 더 빨리 실행됩니다. 주고받습니다.

+0

좋은 지적이지만 컴퓨터의 메모리를 몇 기가비트로 축소시키는 데이터 세트에 대한 테스트를 실행하고 있습니다. 나에게 우려되는 점은 내 오래된 C++ 라이브러리의 비슷한 코드가이 데이터 집합을 처리하는 데 걸리는 시간의 절반에도 못 미치는 시점이라는 것입니다. 그러나 프로필에서 약 2,826 페이지/초가 디스크에 쓰여지고 있으며 응용 프로그램이 메모리 바운드 일 수 있다고 경고했습니다. 명시 적으로 배열을 처리하는 것이 아니며 GC가 할당을 취소하기 전에 캐시 될 수 있습니까? – rnd

+2

이 버퍼는 아마도 85KB보다 큽니다. LOH에서 배정받습니다. 그들은 한동안 붙어있을 것이고, 그것은 gen # 2 컬렉션을 필요로합니다. 무료 일 때는 버퍼를 재사용 할 필요가 없지만 .NET에서는 좋은 전략입니다. –

+0

디스크에서 파일을 강제로로드하려면이 질문과 같이 Windows 파일 캐시를 지우십시오. http://stackoverflow.com/q/478340/80525 – BKewl