Android - [쓰레드의 모든것] 프로세스, 쓰레드, 단일/멀티 쓰레드, 동기/비동기 프로그래밍, 코어 간략 정리

업데이트:

프로세스 vs 쓰레드

안녕하세요.
지금까지 학습해온 프로세스와 쓰레드의 개념부터, 단일/멀티 쓰레드는 물론 동기/비동기 프로그래밍, 코어의 개념을 정리해보았습니다.

우선 프로세스와 쓰레드의 개념부터 알아보도록 합시다.

프로세스

image

프로세스는 간단하게 OS에서 하나의 실행중인 프로그램이라고 할 수 있습니다. 프로세스는 리소스와 쓰레드로 구성되며, 모든 프로세스는 하나 이상의 쓰레드를 가지고 있습니다.


쓰레드

image

쓰레드는 경량화된 프로세스라고 생각하시면 됩니다. 실제로 프로세스 내에서 실제 작업을 수행합니다.
쓰레드는 하나의 프로세스에서 여러 개가 존재할 수 있는데, 이들을 서로 Code, Data, Heap 영역을 공유합니다.


안드로이드에서의 쓰레드

단일 쓰레드

안드로이드에서도 앱을 실행하면 해당 앱의 프로세스가 생성되며, 쓰레드가 하나 할당됩니다. 바로 이 쓰레드가 메인 UI 쓰레드입니다.

그렇다면 여기서 외부 파일을 다운로드 받아야할 경우를 생각해봅시다. 현재 프로세스에는 UI 쓰레드 하나밖에 없기 때문에 외부 파일 다운로드가 시작되는 순간, 앱은 멈추게 됩니다. 즉 다운로드가 완료될 때 까지, 사용자의 상호작용에 반응을 못합니다. 그럼 이렇게 무거운 작업이 있을 경우마다 메인 UI 쓰레드의 작업을 기다려줘야 할까요?


멀티 쓰레드

image

프로세스는 여러개의 쓰레드를 가질 수 있습니다. 별도의 쓰레드를 생성한 후, 이 쓰레드로 하여금 외부 파일을 다운로드를 하도록 하면 UI 쓰레드와 별개로 동작합니다. 이것을 멀티 쓰레딩이라고 합니다.
따라서 UI 쓰레드를 통해 상호작용은 가능하면서 다운로드와 같은 작업은 계속 진행되게 됩니다.

여기서 주의해야할 점은, UI 쓰레드를 제외한 쓰레드는 UI와 상호작용을 할 수 없다는 것입니다. 이 점을 유의하여 핸들러를 통해 메인쓰레드로 해당 코드를 동작시켜야 합니다.

멀티 쓰레드는 보통 비동기식으로 멀티 쓰레드를 많이 사용합니다.


그렇다면 이런 질문이 있을 수 있습니다.

멀티 프로세스?

멀티 프로세스는 여러개의 프로세스를 이용하여 작업을 병렬적으로 처리하는 것을 의미합니다.
이러한 멀티 프로세스를 안쓰고 멀티 쓰레드를 사용하는 이유는 뭘까요?

image

  • 자원의 효율성: 멀티 프로세스로 작업을 수행하면 낭비되는 자원이 많게 됩니다. 멀티 쓰레드를 사용하면 프로세스를 생성하는 자원과 프로세스가 할당되어있는 자원을 절약할 수 있습니다.

  • 메모리 공유: 프로세스간의 통신보다 쓰레드 간의 통신의 비용이 훨씬 적습니다. 왜냐하면 스레드끼리는 대부분의 자원들을 공유하기 때문에 처리 비용이 줄어든다는 이점과, 전환 속도가 빠르다는 이점이 있습니다.


코어

만약 쓰레드를 여러개 생성하였다면 하나의 프로세스에서는 어떻게 동작할까요? 그 배경에서는 코어라는 개념이 있습니다.

코어는 CPU에서 연산을 담당하는 핵심장치입니다. 흔히 우리가 4코어 8쓰레드, 8코어 16쓰레드 라는 말을 많이 들어보셨을겁니다. 그것은 하나의 CPU에 4코어가 있고, 8쓰레드를 할당받아 일을 할 수 있다는 말입니다.

그렇다면 다시, 안드로이드에서 하나의 프로세스와 하나의 UI 쓰레드만 있다고 가정해보겠습니다. 이 상황에서 OS는 해당 프로세스를 1개의 코어에 할당하여 1개의 쓰레드가 동작하게됩니다.

그럼 멀티 쓰레드의 경우는 어떻게 동작할까요? OS가 여유가 있다고 판단하게되면 CPU내의 최대 코어 갯수 만큼의 코어들을 해당 프로세스에 할당하여 쓰레드들이 병렬적으로 동작하게 되는 것 입니다.
예를들어 최대 코어 갯수가 4코어 8쓰레드라고 했을 때, 프로세스 내의 쓰레드가 8개면 최대 4코어를 할당받을 수 있고, 3개면 2코어를 할당받을 수 있습니다.


동기 vs 비동기

동기는 Synchronous, 비동기는 Asynchronous라고 합니다. 그럼 이 둘은 어떤 차이가 있을까요?

동기 방식

동기 방식은 일반적으로 코드가 실행되는 방식입니다. 즉, 요청과 결과가 함께 발생합니다. 요청이 들어오고 결과가 발생할 때 까지 아무 작업을 할 수 없다는 것이죠.

우체국으로 예를 들어 직원을 쓰레드, 손님을 유저라고 가정합시다. 손님 10명이 줄을 서며 자기 차례를 기다리고 있습니다. 직원은 맨 처음 1명의 요청을 받아주고 있습니다. 이 때, 손님이 요청한 결과를 얻기 전 까지는, 다른 손님들은 계속 대기해야 합니다.
이것이 동기 방식입니다.


비동기 방식

비동기 방식은 요청과 결과가 별개로 발생합니다. 요청이 들어와도 결과를 기다리지 않고 계속 요청을 받습니다. 그리고 결과는 순서가 정해져 있지 않고 먼저 작업이 끝난 순으로 발생합니다. 즉, 결과를 간접적으로 전달합니다.

우체국에서 손님 10명이 줄을 서 있지만, 손님 1명의 요청을 듣고 손님을 돌려보냅니다. 그리고 계속 손님을 바로바로 받게 되죠. 결과가 나오게되면 손님이 와서 바로 결과를 받을 수 있습니다.
이것이 비동기 방식입니다.

우리가 흔히 자바에서 사용하는 AsyncTask는 비동기 싱글 쓰레드 방식 입니다. 여기서 ThreadpoolExecutor를 통해 확장하게 되면, 다중 쓰레드 방식이 됩니다.

image


이러한 비동기 프로그래밍을 왜 하는걸까요? 바로 속도입니다.
동기 프로그래밍은 요청이 끝나고 결과가 발생할 때 까지, 무작정 대기해야 하지만 비동기 프로그래밍은 기능 요청을 한 후, 다른 작업을 하고 있다가 이벤트가 발생하면 그 때 처리하면 되기 때문입니다. 특히 DB 호출이 잦은 경우 속도면에서 엄청난 이득이 있습니다.


그러면 비동기 방식과 멀티 쓰레드는 어떤 차이가 있는거죠?

비동기 vs 멀티 쓰레드

멀티 쓰레드는 대부분 비동기 방식과 같이 구현되기 때문에 차이를 잘 논하지는 않습니다. 또한 이에 관련해서 논쟁도 많구요. 실제로 큰 차이가 없습니다.하지만 멀티 쓰레드가 동기식으로 구현되었다면 작은 차이가 있습니다.

동기식 멀티 쓰레드는 비동기식 싱글/멀티 쓰레드와 차이가 있습니다. 예를들어 A쓰레드가 요청을하면 B쓰레드가 요청을 받습니다. 이후 B쓰레드가 작업을 하여 그 결과를 반환해야 A쓰레드가 동작하게 됩니다.


결론

지금까지 프로세스와 쓰레드를 중점으로 알아보았습니다.

비동기 다중 쓰레드 방식이 마냥 좋은 것 같지만 그렇지만은 않습니다. 쓰레드를 많이 사용하게되면 동기화 문제 같은 쓰레드 제어에 대한 노력이 많이 들어가게 되며 버그도 많이 발생할 수 있을 뿐더러, 프로그래밍 난이도가 가파르게 상승하게 됩니다. 물론 비동기 다중 쓰레드 방식을 사용하면 그런 노력을 하고도 남을 만큼, 프로그램이 엄청난 속도 향상을 한다는 것을 알 수 있을 겁니다.

저의 생각과 몇몇 참고자료를 통해 글을 작성해보았습니다. 혹시 잘못된 부분이나 궁금하신점 있으시면 댓글 달아주시면 감사하겠습니다!


참고자료


댓글남기기