brunch

You can make anything
by writing

C.S.Lewis

by 이승현 Feb 20. 2017

Threading Performance #03

AsyncTask

#01 Communication with UI Thread


시간이 오래 걸리는 작업은 ANR 방지나 성능 이슈를 줄이기 위해 별도의 작업자 스레드를 통해 처리하고, 이를 바탕으로 다시 UI 스레드에서 처리해야 합니다.


이를 위해 안드로이드는 Helper 클래스들을 제공하고 있습니다.




AsyncTask


AsyncTask를 사용하면 사용자 인터페이스에서 비동기식 작업을 수행할 수 있게 해줍니다.

작업 스레드에서 작업을 수행하고 그 결과를 UI 스레드에 전달하여, 개발자가 직접 스레드 및 핸들러를 처리할 필요가 없습니다.


#02 AsyncTask


onPreExecute()

작업이 실행되기 전에 UI 스레드에서 호출됩니다.

일반적으로 수행하려는 작업을 설정하는 데 사용됩니다.


doInBackground()

실제로 작업을 실행하는 작업 스레드에서 호출됩니다.

오랜 시간이 걸릴 수 있는 백그라운드 작업을 실행하는 데 사용됩니다.


postExecute()

백그라운드 계산이 끝난 후 UI 스레드에서 호출됩니다.

백그라운드 작업의 결과는 이 단계에 매개 변수로 전달됩니다.


굉장히 단순하고 사용하기 편하기 때문에 많이 쓰이지만, 몇 가지 성능 이슈를 일으킬 수 있습니다.




Block and Wait


#03 AsyncTask.execute several times


생성된 모든 AsyncTask는 동일한 메인 스레드를 공유하므로 단일 메시지 대기열(single message queue)에서 연속적으로 실행됩니다.

따라서 하나의 작업이 예상보다 오래 걸린다면 완료될 때까지 나머지 작업들은 계속 기다려야 합니다.

자칫하면 무한정 기다리는 상황도 생길 수 있기 때문에 이는 좋은 방법이 아닙니다.




#04 AsyncTask.executeOnExecutor


공정하게 Asynctask가 스레드 풀(thread- pooled) 방식으로 실행되도록 하는 방법이 있습니다.

그러나 여러 작업을 스레드 풀에서 병렬로 실행하도록 허용하는 것은 일반적으로 작업 순서가 정의되어 있지 않기 때문에 좋지 않습니다.




Cancelling a task


현재 실행 중인 스레드를 취소시키기 위한 Thread.stop() 메서드가 존재하지만 Deprecated 상태입니다.

즉, 안드로이드에서는 현재 실행 중인 스레드를 직접 취소하는 메서드는 없습니다.

#05 Thread.stop()


아래와 같이 Thread.interrupt() 메서드를 이용해 직접 구현해야 합니다.




AsyncTask는 cancel(boolean) 메서드를 호출하여 작업을 취소할 수 있습니다.

하지만 cancel(boolean) 메서드 호출을 해도 그 즉시 AsyncTask 실행이 멈추지 않습니다.

(doInBackground() 메서드 로직이 완료된 후에 onCancelled()가 호출됩니다.)

따라서 실행 중 가능한 한 빨리 작업을 취소하려면 두 가지 일을 해야 합니다.


1. Check a "canceled" flag

isCancelled() 메서드가 true를 반환하는지 검사하여 일찍 종료해야 하는지 확인합니다.


2. Report work results invalid

취소된 AsyncTask는 postExecute() 대신 onCancelled() 메서드를 UI 스레드에서 호출합니다.

취소된 결과에 따른 UI 업데이트도 여기서 구현해야 합니다.


#06 AsyncTask cancel codes




Memory leak


#07 Inner AsyncTask class


흔히 볼 수 있는 AsyncTask를 Actvitiy의 내부 클래스(inner class)로 선언하고 있는 코드입니다.

내부 클래스로 선언된 AsyncTask를 사용하면 외부 Actvitiy에 대한 암시 적 참조가 만들어 지므로 메모리 누수가 생길 수 있습니다.

즉, AsyncTask작업이 완료될 때까지 Actvitiy instance의 메모리 영역이 GC에 의해 해제되지 않습니다.


내부 클래스로 선언된 AsyncTask의 메모리 누수 문제는 아래 글을 참조해주세요.




쓰기 편한데 몇 가지 이슈가 존재하네요.

Cancelling a task, Memory leak 두 가지 이슈는 코드 상 처리할 수 있지만, Block and Wait 이슈는 AsyncTask로 처리하기 쉽지 않습니다.

상황에 따라 적절한 Helper 클래스들을 이용하기 권장합니다.


영상을 보고 처음 알았는데 AsyncTask를 "어싱크 태스크" 가 아닌 "에이 싱크 태스크"라고 말하네요.

안드로이드 개발 5년 차에 처음 알았습니다....


좀 더 자세한 내용은 아래 링크와 영상을 보시기 바랍니다.


브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari