2012-05-29 2 views
3

개요한 번에 여러 비트 맵에서 작업하면서 성능을 향상시키는 방법은 무엇입니까?

ViewStyle을 vsIcon으로 설정하여 TListView를 채우고 있습니다. Listview는 TImageList에 연결되어 있으며 Listview에 추가 된 각 항목에 대해 해당 색인에 지정된 자체 이미지가 있습니다.

아이디어는 한 번에 일련의 비트 맵을 조작하는 프로세스를 자동화 할 수 있다는 것입니다. 각 비트 맵은 항상 크기가 같지만 다르다.

이 작동 방식의 특성으로 인해 ImageList에 몇 개의 비트 맵이 추가되었는지에 대한 고정 된 크기 나 제한이 없으므로 사용 가능한 시스템 메모리 만 제한됩니다.

문제

나는이 비트 맵에 대한 조작의 성능과 관련이있는 문제. 조작이란 그레이 스케일, 색상 바꾸기, 밝기 조정 등과 같은 비트 맵에서 다른 이미지 처리 기술을 수행하는 것을 의미합니다.

이제 1Mb 크기의 비트 맵 밝기를 조정하는 데 3 초가 걸린다고 가정합니다. ImageList에 총 10 개의 비트 맵이있는 경우이 프로세스는 이제 약 30 초가 걸립니다.

(참고 : GetTickCount 또는 그 밖의 속도로 테스트하지는 않았지만 이는 예제 일뿐입니다.)

이전에 ImageList의 크기가 아무 것도 될 수는 없지만 잠재적으로 처리 시간은 영원처럼 보일 수 있습니다.

나는이 같은에서 조작을 수행하기 위해 내가 오프 스크린 버퍼 비트 맵에 각 비트 맵을 전송하는 루프 내부에 GetBitmap를 사용하여 이러한 비트 맵에 어떤 조작을 수행 할 때 :

var 
    Bmp: TBitmap; 
    i: Integer; 
begin 
    Bmp := TBitmap.Create; 
    try 
    ImageList1.BeginUpdate; 
    try 
     for i := 0 to ImageList1.Count - 1 do 
     begin 
     ImageList1.GetBitmap(i, Bmp); 
     Bmp.PixelFormat := pf24Bit; 
     // perform manipulation to Bmp here 
     ImageList1.Replace(i, Bmp, nil); 
     end; 
    finally 
     ImageList1.EndUpdate; 
    end; 
    finally 
    Bmp.Free; 
    end; 
end; 

실행을하는의 ImageList를 통해 그 어떤 크기 나 양의 이미지를 포함 할 수 있으며 이것이 어떻게 느릴 수 있는지 이해할 수 있습니다.

나는 이것을 수행하는 방법을 최적화하고 개선하는 방법을 찾고 있는데, 지금은 받아 들일 수있는 성능이 현명한 곳에서는 어디에도 없습니다. BeginUpdateEndUpdate은 여기에 가치있는 해결책을 제공하지 않습니다. 나는 대부분의 계산이 긴 처리 시간을 필요로한다는 것을 이해함에 따라 어떤 기적을 찾지 않고 있으며, 당신이 제공해야 할 도움이나 조언으로 가능한 한 최선을 다해이 시간을 줄여야합니다. 이는 침체가 일어나고있는 사실에 있는지 확인하기 위해 코드를 프로파일 링 할 때까지

0) 아무것도하지 마십시오

+2

멀티 스레딩은 필요한 방식이지만 모든 것이 아니라 스레드 풀이 필요합니다. OmniThreadLibrary는 이렇게 할 수있는 훌륭한 자원을 가지고 있습니다. http://otl.17slon.com/ http://otl.17slon.com/ 한 번 시도해 보았습니다. 한번에 700 개의 스레드 (700 개 이미지를 가정)를 만들려고 시도하지 않았습니다. 말 그대로 컴퓨터를 죽일 것입니다. 쓰레드 풀의 개념은 5 개의 쓰레드를 동시에 실행하는 반면 나머지는 기다리는 대기열에 머무르는 것입니다. 한 스레드가 완료되면 다른 스레드가 종료되므로 한 번에 5 개의 스레드가 실행되지 않습니다. –

+0

스레드에 의해 @ JerryDodge 당신은 CPU에서 각각의 사용 가능한 코어를 활용한다는 것을 의미합니까? –

+1

아니요, 그는'TThread'를 사용한다는 의미입니다. 동시에 실행되므로 여러 이미지를 동시에 처리 할 수 ​​있으며 응용 프로그램 UI는 반응 형으로 유지됩니다. 이론 상으로는 OS가 쓰레드를 교체 할 스레드를 찾아 낼 수 있다면, 걱정할 필요가 없습니다. –

답변

4

개인적으로, 나는 몇 가지 일을 할 것입니다.

1) TImageList를 사용하는 대신 TList 하위 항목을 사용하여 이미지를 저장합니다. 이것이 성능에 직접적인 영향을 미치는지 확신 할 수 없지만 IIRC, TImageList는 내장 된 Windows 이미지 처리에 많이 의존합니다. 느린 것일 수 있습니다.

2) 가능한 경우 모두 함께가 아니라 필요에 따라 이미지를 업데이트하십시오.

3) 변환 프로세스를 주 스레드에서 실행하지 말고 스레드하십시오.목록 항목을 스레드 (또는 스레드 대기열)에 전달할 수 있으므로 TList를 사용하는 경우 매우 간단합니다. 사용 가능한 경우 다중 프로세서를 사용하는 이점이 있습니다.

스레딩은 실제로 시간이 오래 걸리지 않을지라도 앱의 인식 성능을 향상시킬 가능성이 가장 큽니다. 이를 필요한 전환으로 결합하면 큰 발전을 볼 수 있습니다.

ETA : Jerry에서 언급 한 스레드 풀이 좋은 아이디어입니다. 블로그를 검색하면 some examples of this on the Embarcadero site 명이 있습니다.

+0

Tim이 언급했듯이 'TImageList'가 매우 무거 우므로 'TList'를 사용하면 성능이 확실히 향상됩니다 (밀리 초 단위 일지라도). 그러나 이렇게하면 목록 항목이 링크 된 이미지를 자동으로 표시하는 기능이 다시 사용됩니다. 즉, 이러한 이미지를 수동으로 그릴 필요가 있음을 의미합니다. 여전히 가능하지만 꽤 복잡합니다. 나는 여전히 이것을 권장하지만, 목록에 보여줄 로딩/프로세싱 이미지는 쉬운 일이 아니므로 조심해서 다루어야한다. 아이러니하게도, 오늘 나는 정확히 (TListView 대신 그리드에서만)이 작업을 수행했습니다. –

+0

스레드로 처리를하는 것은 내가하는 것처럼 보입니다. 물론 주 스레드에서 실행하는 것은 분명히 느리고 Application.ProcessMessages에서도 응답하지 않습니다. TList에 이미지를 저장하는 것도 ImageList보다 좋을 수 있습니다. 이것들은 내가 그것을 구현하는 방법을 더 잘 이해하기 위해 연구해야하는 모든 것입니다. 이것은 제가 직접해야 할 질문들 중 하나입니다. 나는 그 속도가 한 비트 맵에서 같은 것을 수행하는 것이 상대적으로 빠르기 때문에 변형 된 비트 맵의 ​​무한한 양이 있다는 사실 때문에 속도 저하가 있음을 안다. –

1

Tim의 훌륭한 제안에 추가되었습니다. 비트 맵에 액세스하는 방법을 모르겠 으면 비트 맵의 ​​ScanLine 속성을 사용하십시오. 가능한 한 pf32Bit을 사용하면 액세스가 더 쉽고 대개는 더 빠릅니다.

비트 맵은 스레드 안전하지 않습니다. 스캔 라인을 읽는 것은 문제가되지 않지만 결과를 다시 쓰고 싶을 때는 중요한 섹션이나 그와 비슷한 것을 사용해야합니다.

프로파일 러를 사용하는 것이 좋습니다. 어떤 코드가 비효율적인지 아닌지에 놀랄 것입니다. ProDelphi를 사용합니다 : 비용이 많이 들지 않고 정확합니다.

+2

왜 32 비트 비트 맵이 * 더 쉽고 빠르게 액세스 할 수 있습니까? 조금 더 자세히 설명해 주시겠습니까? 그리고 scanline *을 읽는 것과 같은 것은 없습니다. scanline은 여러분이 직접 조작 할 수있는 raw 픽셀 데이터에 대한 포인터를 제공합니다. – TLama

+0

@Arnold 그는 스캔 라인을 독자적으로 읽고 이미지 데이터의 실제 복사본을 검색 할 수 없다는 것을 의미합니다. 대신 단지 이미지 데이터를 찾을 수있는 메모리 조각을 가리키고 있습니다. –

+0

추신 : 나는 지난 코멘트의 시작 부분에 실수로 오타가 있었기를 바랍니다. –

관련 문제