오늘은 비동기와 블록킹이라는 개념에 대해 공부해볼 예정이다.
먼저 프로그램이란 무엇인지에 대해 알아 보자. 프로그램은 명령어(코드)들을 순서대로 실행하는 것이다. 당신은 프로그램 하나를 짰고, 여러 가지 기능들이 포함돼있다. 음 근데, 그 중 C라는 기능를 실행하는데 무조건 5초가 걸린다고 한다. 해당 기능 때문에 프로그램의 모든 코드를 수행하는 시간이 5.5초가 걸렸다. 기능 C 하나 때문에 기능 D와 기능 F를 실행 못하고 5초를 기다린 비효율이 발생한 것이다.
이러한 프로그램을 Syncronous, 즉 동기화 프로그램이라고 한다. Function C가 오래걸리더라도 실행하고 다음 단계로 넘어가는 과정을 볼 수 있었다. 그 반대는 무엇일까. 일단 확실한 것은 Function C를 기다리지 않고 다음 기능들을 바로 수행할 수 있을 것만 같다.
정확하다. 정체가 무엇인진 모르겠지만, 녹색 화살표 녀석이 "내가 Function C를 수행할테니 다음꺼 실행해!"라고 했다. 덕분에 Function C를 기다리지 않고 나머지 Function D, F를 즉각 수행할 수 있었다. Function C는 Function F가 수행되고 4.7s 뒤 쯤에 종료됐을 것이다.
이러한 프로그램을 Asyncronous, 즉 비동기 프로그램이라고 한다. Function C의 수행과 종료를 지켜보지 않고 다른 쓰레드에게 작업을 전가하고 나머지 프로그램을 실행시켰다. Asyncronous의 앞부분을 따서 Async라고 부르는데, 비동기와 관련된 AsyncTask라는 기능을 들어봤을 것이다. 동기/비동기에 알고 나니 쓰레드에 대한 간단한 이해도 필요하겠다.
지금까지 종종 들어왔던 JAVA의 Thread 클래스, Runnable 인터페이스, Kotlin Coroutine, 안드에서 UI handler를 다루는 AsyncTask 등은 이 비동기 프로그래밍을 위한 것임을 이해하고 넘어가자. 자 그렇다면, 이 비동기 프로그래밍이 가장 흔하게 사용되는 곳이 어딜까.
바로 네트워킹이다.
Server Architecture Pattern에서 서버는 클라이언트의 요청을 받고 응답 및 데이터 전송 처리를 해준다고 했다. 50개의 클라이언트가 하나의 서버에 데이터 요청을 할 때 쓰레드, 비동기 개념이 없었다면 어떻게 될까. 내 클라이언트가 50번째 순서로 데이터 요청을 했다면 앞의 49대의 요청-응답-데이터 전송 처리를 기다려야 했을 것이다. 서버는 이 때 멀티쓰레딩을 한다. 여러 개의 쓰레딩을 통해 동시에 여러 클라이언트의 요청을 받고 처리하는 작업을 수행할 수 있게 되는 것이다.
또한, 안드로이드에는 3개의 쓰레드 종류가 존재한다.
쓰레드의 종류에 대해 간략히 알고 해당 글을 읽으면 이해가 잘 될 것이다. 각종 다양한 정보들을 찾아보며 글을 쓰고 있는데, 이 정도로 퀄리티로 블로그 글을 올리시는 분들에 존경심이 생긴다. 아무튼! 읽고 오면 좋겠다.
위의 키워드들은 동기와 동기/비동기를 설명할 때 등장하곤 한다.
sender(server)가 1GB 버퍼를 가지고 있는 receiver(client)에게 5GB 영화를 전송해준다고 가정하자. 데이터를 전송 받는 receiver의 속도가 데이터를 전송하는 sender의 속도보다 느리면 receiver가 5GB 데이터를 다 받을 때까지 대기할지/말지를 sender는 결정해야 한다. 이 때
이는 sender의 입장이다. 입장을 바꿔 이번엔 데이터 전송에 있어 receiver가 sender의 속도보다 빠르면 receiver도 sender가 데이터 전송을 마칠 때까지 대기할지/말지를 결정해야 한다.
결국 blocking - non-blocking은 상호작용 중인 상대방 프로세스의 작업이 마칠 때까지 대기하는가/하지 않는가에 대한 개념이다. 왜 블록킹이라는 개념이 동기/비동기와 관련된 개념인지 블록킹-논블록킹의 장/단점에 대해서 알아보자.
Blocking
장점
두 프로세스의 상태/상황이 동기화된다(결과를 return 받을 때까지 대기한다)
단점
프로세스의 작업이 다 끝나더라도 다른 한쪽의 작업이 끝날 때까지 대기하는 비효율이 수반될 수 있다.
non-Blocking
장점
대기하지 않고 다음 작업을 바로 수행할 수 있다. 해당 프로세스 작업의 비효율이 발생하지 않는다.
쓰레드의 관점에서 보면, 하나의 쓰레드가 여러 개의 I/O 처리가 가능하다.
단점
두 프로세스의 상태/상황이 비동기화됨으로써 올 수 있는 불이익/문제들을 감수해야 한다.
동기/비동기에 대한 이해가 얼추됐다면 콜백메소드에 대한 이해도 할 수 있겠다. 콜백메소드는 비동기 네트워크에서도 사용된다.
Sync / Async
Thread
blocking / non-blocking
이해가 간략적으로 되었는가? 그렇다면 Coroutine에 대해 공부할 자격이 충분하다. 가보자!