brunch

You can make anything
by writing

C.S.Lewis

by 이승현 Feb 07. 2017

Threading Performance #01

Handler Thread, Main Thread Performance

Thread를 잘 사용하면 앱의 성능을 향상할 수 있습니다.

그만큼 중요한 개념 중 하나이며, 잘 정리된 글들도 쉽게 찾을 수 있습니다.


https://developer.android.com/guide/components/processes-and-threads.html?hl=ko




#01 Default Thread


Thread는 기본적으로 세 단계(Begin, Do work, End)를 거치고 사라지게 됩니다.

크고 복잡한 안드로이드 환경에서 이용하기에는 너무 단순한 구조이기에 개선이 필요합니다.


#02 Improved Thread


우선 Thread의 작업이 끝나면 사라지기 때문에, Thread를 계속 실행하려면 Loop를 실행해야 합니다.
(Loop를 종료할 수 있는 종료 조건도 반드시 정의해야 합니다.)

Loop가 작업 블록을 가져와서 실행할 수 있는 일종의 작업 Queue도 필요합니다.

작업 블록을 생성하고 실행을 위해 Work Queue에 전달하는 별도의 Thread가 필요합니다.


이를 직접 개발하기엔 쉽지 않습니다.

다행히도 안드로이드에서는 이러한 기능을 수행하는 클래스들을 기본으로 제공하고 있습니다.


#03 Looper

Looper 클래스는 Thread에 대한 Message loop를 실행하는 데 사용되는 클래스입니다.

(Thread는 기본적으로 자신의 작업이 끝나면 사라지기 때문에 Message loop가 없습니다. )

간단히 말해서 아래 코드 [for(;;)]처럼 무한 루프를 돌며 Message Queue에 들어온 작업을 차례로 꺼내서 이를 처리하는 클래스입니다.


loop() 메서드 코드 살펴보면 내부적으로 어떻게 동작하는지 확인할 수 있습니다.

내부적으로 Message Queue 하나를 생성합니다.

무한 반복을 시작하고 매 반복마다 Message Queue에서 하나의 Message를 추출합니다.

Looper는 추출된 Message를 처리합니다.


#03-3 Looper.java 처리 과정



#04 Handler

Handler 클래스는 Looper가 Message를 처리할 수 있도록 Message Queue에 Message를 추가하는 클래스입니다.


Looper는 내부적으로 static Looper 객체와 Message Queue를 가지고 있습니다.

즉 Looper를 정적으로 선언했기 때문에 어디서든 참조할 수 있고, 언제든지 이를 통해 Message Queue에 Message를 추가할 수 있다.


안드로이드는 이 Looper를 제어하기 위한 Handler 객체를 제공하고 있습니다.

결국 어떤 Thread에서라도 Handler 객체만 생성하면, Handler 객체 내부적으로 Looper 객체를 참조할 수 있게 됩니다.


Handler 객체는 Thread에서 생성된 Looper 객체를 참조하고 있습니다.

생성된 Message는 Handler 객체를 이용하여 Thread의 Message Queue에 추가할 수 있습니다.

#04-1 Handler.java [생성자]
#04-3 Handler.java [sendMessage(Message msg)]


#05 Intent, Runnable, Message


Message는 Thread 간 통신할 데이터를 가진 객체이자 Queue에 들어갈 일감의 단위로 Handler를 통해 보낼 수 있습니다. 

#05-1 Handler.java [sendMessage(Message msg)]


Message가 int나 Object같이 스레드 간 통신할 데이터를 가진다면, Runnable은 실행할 run() 메서드와 그 내부에서 실행될 코드를 가진다는 차이점이 있습니다.

#05-2 Handler.java [post(Runnable r)]


https://realm.io/kr/news/android-thread-looper-handler/




1. Handler Thread


#06 HandlerThread


이 모든 것을 합쳐진 것이 HandlerThread입니다.

코드를 보시면 Thread를 상속받아 구현된 클래스인데, 차이점은 내부적으로 Looper를 가지고 있습니다.

즉 Looper 내부의 Message Queue를 이용해 Message나 Runnable 객체를 받아 처리할 수 있습니다.


#06-1 HandlerThread.java


https://realm.io/kr/news/android-thread-looper-handler/




2. Main Thread


사용자가 앱을 실행하면 안드로이드는 새로운 Linux Process와 함께 Handler Thread로 만들어진 Main Thread를 생성합니다.

이 Main Thread(UI Thread)는 화면에서 발생하는 모든 작업을 담당합니다.

Life cycle 정보(시스템 이벤트)와 관련된 Callback 또는 입력 이벤트의 Callback 또는 다른 응용 프로그램의 이벤트 일 수도 있습니다.


#07 Main Thread


즉 개발자가 작성한 대부분의 코드가 Main Thread에서 동작하게 됩니다.

#07 Main Thread




3. Threading performance


Main Thread에서는 애니메이션 또는 화면 업데이트가 진행되는 동안 초당 60 프레임을 매끄럽게 렌더링 하기 위해 16ms마다 작업을 실행합니다.


#08 Main Thread (UI Drawing)


만약 그 중간에 임의의 작업이 예상보다 오래 걸리는 경우, 16ms 내에 다음 프레임을 렌더링 할 기회를 놓치고 해당 프레임이 지연됩니다. 이를 Dropped Frame이라 부르고 사용자에게 불편을 초래합니다.


#09 Main Thread (Dropped Frame)


이를 방지하게 위해 작업 시간이 오래 걸리거나, 많은 양의 작업은 Main Thread가 아닌 별도의 Thread를 통해 처리해야 합니다.

#10 Main Thread (Worker Thread)




4. Helper Classes for Threading


안드로이드는 Threading에서 발생할 수 있는 성능 이슈를 줄이기 위해 여러 가지 Helper 클래스들을 제공하고 있습니다.

AsyncTask

HandlerThread

ThreadPool

IntentService


각각의 클래스에 대한 내용은 다음에 작성할게요ㅠㅜ





사실 안드로이드 Thread에 대해 글을 쓰고 싶지 않았습니다.

이미 잘 정리된 좋은 글들도 많이 있기도 하고,

개인적으로 좋아하지 않습니다. ㅎㅎ


안드로이드에서 Multithreading를 쓰는 주된 이유는 ANR을 방지하기 위해서 이지만,

성능과 관련된 내용을 적다 보니 굳이 관련된 내용은 기재하지는 않았습니.


자세한 내용은 아래 글과 영상을 보시기 바랍니다.


https://developer.android.com/topic/performance/threads.html#references


https://www.youtube.com/watch?v=qk5F6Bxqhr4&index=1&list=PLWz5rJ2EKKc9CBxr3BVjPTPoDPLdPIFCE

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