. 다른 정렬 방법

이 예제가 선택한 정렬 최적화 방법은 최대한 이전 정렬 결과를 재활용하는 방법이었는데 이 방법과는 아예 질적으로 다른 정렬 방법을 선택할 수도 있다. 정렬 알고리즘이 어떻게 더 최적화될 수 있는지 가능한 방법 몇 가지에 대해 간단하게 고찰해보도록 하자. 정렬은 텍스트 편집기의 속도를 가늠하는 가장 중요한 기능이기 때문에 이 방법에 대해서는 아주 많은 생각을 할 필요가 있고 항상 최적화를 고민해야 한다.

 

정렬 무효화

이 방법은 마치 화면을 무효화하듯이 문서에 변화가 생기면 정렬할 필요가 있는 부분을 무효화시켜 놓는 것이다. pLine 배열에 bValid 같은 멤버를 추가하고 이 멤버에 무효 여부를 기록하면 될 것이다. 무효해진 정렬정보는 필요할 때 필요한 만큼만 유효화를 한다. 정렬정보가 필요한 경우는 화면출력시, 캐럿이동시, 선택시 등인데 화면에 출력할 만큼만 정렬해놓고 나머지는 무시하는 것이다.

당장 쓰이지 않는 부분은 정렬을 하지 않음으로써 정렬에 드는 막대한 시간을 절약할 수 있다. 이 방법의 단점이라면 갑자기 <Ctrl+End>로 문서 끝으로 갈 때 굉장히 반응이 느려질 수 있다는 점이다. <PgDn>으로 스크롤할 때도 그때그때 정렬을 하므로 이동 속도가 둔해진다. 또한 문서의 총 길이를 정확하게 모르는 상황이기 때문에 수직 스크롤바의 범위가 부정확해진다.

백그라운드 정렬

말 그대로 뒤에서 찔끔찔끔 나누어 정렬을 하는 방식이다. 물론 당장 필요한 부분은 급하게 정렬을 해야 한다. 이 방법도 썩 괜찮은 방법이기는 하지만 컨트롤이 되면 백그라운드 정렬 시간을 할당 받기 위해 메인 메시지 루프를 건드려야 한다는 부담이 있다. 아니면 타이머 메시지를 사용해야 하는데 알다시피 타이머 메시지는 속도가 느려서 쓰기 어렵다.

백그라운드 정렬은 본질적으로 작업을 나누어 하는 방식이기 때문에 전체 정렬이 필요할 때 정렬 속도는 그야 말로 형편없다. 또 항상 백그라운드 정렬을 하려면 어느 정도의 CPU 시간을 축내야 하는데 이는 전체적으로 시스템 효율을 떨어뜨리는 좋지 않은 효과가 나타난다.

어셈블리 도입

정렬 루틴의 핵심 부분을 어셈블리어로 다시 쓰면 코드의 절대적인 실행속도가 빨라질 것이다. 어셈블리는 C 언어보다 평균적으로 2~10배 가량 빠르므로 최적화된 코드의 경우 똑같은 알고리즘이라도 상당한 속도 향상 효과가 있다. 그러나 쓰기도 어려울 뿐더러 유지하기는 더 어렵다는 것이 단점이다. 프로젝트의 모든 코드가 다 작성된 상황이라면 마지막 단계로 고려해 볼만한 방법이며 실제로 적용할 계획을 가지고 있다.

멀티 스레드

백그라운드 작업을 좀 더 발전시키면 멀티 스레드를 생각할 수 있다. 스레드는 OnIdle이나 타이머 메시지보다는 훨씬 더 부드럽게 작동하므로 상당히 좋은 결과를 기대할 수 있다. 하지만 멀티 스레드는 동기화라는 어려운 문제가 있고 그 자체가 복잡해서 웬만하면 피하는 것이 좋다고 생각한다.

실제로 ApiEdit의 정렬루틴을 멀티 스레드로 만들기 위해 시도를 해 봤는데 하루 정도 작업해 본 결과 현재 구조로는 어림도 없다는 결론에 도달했다. 정렬루틴을 멀티 스레드로 만드는 것은 어렵지 않으나 정렬 중에 문서 상태가 바뀌는 경우를 처리하기가 너무 어려웠다. 이 경우 하던 정렬을 그만 두고 처음부터 다시 정렬해 와야 하는데 그러자니 이전 정렬 스레드가 만들다 만 pLine이 문제가 되었다. 뿐만 아니라 여기 저기서 동기화 문제들이 터져 나와 아예 정렬방식을 바꾸지 않는 한 멀티 스레드 정렬은 당분간은 어려울 것 같다.

 

이상의 방법 외에도 정렬루틴을 최적화할 수 있는 방법은 아주 많다. 각각의 방법이 다 나름대로의 장점과 단점이 있는데 어떤 방법을 선택할 것인가는 개발자의 능력과 취향에 따라서 선택할 문제이다. ApiEdit는 통째로 정렬하되 정렬 범위를 최소화하는 방법을 선택했을 뿐이며 차후에 내공이 더 높아지면 다른 방법도 시도해 볼 것이다. 지금 능력으로는 여기까지가 한계점임을 솔직히 고백하지 않을 수 없다.