흐르는 시간의 블로그...

페이스북의 GOLang 커뮤니티에서 아래의 글이 링크되었다.

Deferred Funcs

해당 글은 defer에 대해 매우 쉽게 잘 설명해주고 있다.

내용중에 인상적인 부분은 Deferred closure 이다.

최근 텍스트파일을 읽어서 데이터 분석을 했었다.

분석시 해당 데이터 전체의 시작과 끝점을 기록할 필요가 있었다.

문제는 끝점이 정확히 검색이 되는 경우이지만 그렇지 않은 경우 여러 조건절을 통해 끝점을 찾아야 한다.

나쁜 경우는 내용전체를 돌면서 최종 기록을 끊임없이 반복하여 기존 변수에 할당해야 하는 것이다.


for err != io.EOF {
if xxxx { ...... ......
(CarsInfo[lID][dDate][rNo]).endTime = "20" + string(lines[11:23])
beforeSpeed = nowSpeed
}

n, err = rc.Read(lines) } // 마지막 라인 if xxx { (CarsInfo[lID][dDate][rNo]).endTime = "20" + string(lines[11:23]) }

이런 경우 deferred closure를 사용하면 성능을 좋게하면서 코드를 깔끔하게 할 수 있다.

위의 링크의 예제코드이다.

defer func() 내에서 조건문을 사용하여 작업을 할수도 있고 정해진 구조라면 마지막의 일부 데이터만 추출하여 사용할 수 있다.

만약  for 루프가 10000번 실행된다면 10000번의 할당작업의 성능을 아낄수 있다.


defer func () {

(CarsInfo[lID][dDate][rNo]).endTime = "20" + string(lines[11:23])

}() for err != io.EOF {
if xxxx { ...... ......
beforeSpeed = nowSpeed
}

n, err = rc.Read(lines) }


현재 개인적으로 개발한 분석 코드에서의 수정 결과를 체크해보자.

할당에 대한 CPU 타임은 크지 않으므로 아주 큰 효과는 없으리라 본다.


테스트 환경 / 결과

12코어(TOP 표기상 24코어)중 절반 사용

평소 100% idle (완벽히 노는 서버)

worker 20개로 버퍼채널 이용

20398개의 ZIP 파일을 zip package를 이용해서 압축을 풀면서 분석

캐쉬 상황을 고려하여 번갈아가며 3회 반복(압축을 풀면서 작업하기에 캐쉬관련 이슈는 없지 싶지만서도...)

평균 15초 이상 줄어든다

기존 코드 결과

job ends. execute time: 3m14.353966626s

job ends. execute time: 3m16.453676824s

job ends. execute time: 3m15.367271724s

deferred closure 사용 결과

job ends. execute time: 3m0.899630867s

job ends. execute time: 2m59.410079684s

job ends. execute time: 2m52.597714407s


결론

꽤 괜찮다. 적극적으로 사용할만한 패턴이라 생각된다.