[iOS] 차근차근 시작하는 GCD — 3

sync vs async (동기 vs 비동기) 를 알아봅시다

naljin
8 min readOct 10, 2020

Previously on GCD…

우리의 메인 스레드 (thread 1)가 모든 일을 하고 있는 상황!

쏟아지는 일들을 다른 스레드들로 나누기로 결심한 메인 스레드..!! 이를 위해서 작업들을 queue로 보내기만 하면 된다! 라고 했어요~

스레드에 분배는 GCD가 알아서 해준다는 말에 일단 큐에 작업 한 개를 보낸 우리의 메인 스레드..!

자자 queue에 작업을 보내고 난 후 메인 스레드의 행동은 어떤걸까요?

  1. 신경 끄고 자기한테 쌓여있는 다음 일을 한다

2. 끝날 때까지 기다린 후에 자기한테 쌓여있는 다음 일을 한다

이게 바로 비동기와 동기의 개념입니다.

여기서 “메인 스레드가 자기한테 쌓여있는 다음 일을 실행한다”라는 것은 쉽게 “다음 라인을 실행한다”로 생각하면 될 것 같아요

비동기 (async)

그래요.. 저는 이름부터 어려워 보여서 싫어해요.. 하지만 어쩌겠어요 친해져야지..

자기만 일하는 사실에 화가 난 메인 스레드가 queue에 일부 작업들을 보내고 난 후 취할 수 있는 첫번째 행동은 뭐였져?

신경 끄고 다음 라인 실행 한다

이게 바로 비동기의 개념입니다.

queue에 보낸 작업에 대해서는 더 이상 신경 안 씀요! 바로 다른 일 해버리기! 보낸 작업에 걸렸을 시간 만큼 또 다른 일을 할 수 있을 거예요.

코드로 봅시다

DispatchQueue.global().async {
//task
}

저번 시간에 해당 코드를 하나씩 뜯어봤어요.

  • DispatchQueue: iOS에서 동시성 프로그래밍을 돕기 위해 제공하는 queue
  • global: DispatchQueue의 종류
  • async: 비동기

한글로 해석해보자면

global dispatch queue에 비동기로 task를 보낸다

라고 했었는데, 여기서 async를 좀 더 풀어서 설명해보자면

원래의 작업이 진행되고 있던 메인 스레드에서 global dispatch queue로 task를 보낸 후, 해당 작업이 끝나기를 기다리지 않고 이어서 할 일을 한다

가 되겠네요!

자 좀 더 긴 코드를 봅시다

윗 빗금에서 밑 빗금까지 main thread에서 실행하는데는 얼마나 걸릴까요?

정확히는 체크해봐야 알겠지만 6초보다는 훨~씬 덜 걸리겠다 까지는 감이 오시나요? 제가 돌려 봤을때는 약 0.00044초 정도 나오네요.

왜냐면 메인 스레드에서는 작업을 queue에 넘기고 나면 더 이상 해당 작업에 대해선 신경 쓰지 않고, 남아있는 자기 할 일을 하니까요!

앗, 참고로 우리가 별도의 작업을 하지 않았다면 코드가 동작하고 있는 곳은 main thread 랍니다. 이러한 메인 스레드의 입장을 정리해보자면..

  1. 작업을 큐에 던졌다?
  2. 그게 1초가 걸리는 작업이든 1시간이 걸리는 작업이든 아 돈 케어~
  3. 쿨하게 나한테 남아있는 다음 작업 고고!

그림으로 다시 설명해볼게용

첫 줄에서 시작하는 메인 스레드. Dispatch.global() 으로 queue 생성.
다음 라인이 task를 보내는 코드여서 신난 메인 스레드
이전 코드에서 async로 보내서 다음 라인 바로 실행이 가능한 메인 스레드
다음 라인도 task를 async로 보내는 코드를 만난 메인 스레드
이전 코드에서 async로 보내서 다음 라인 바로 실행이 가능한 메인 스레드
다음 라인도 task를 async로 보내는 코드를 만난 메인 스레드
어느새 모든 실행 라인이 끝난 메인 스레드

이런 상황인데.. 이해에 도움이 되시려나요?!

추가로 이런 의문이 들수도 있을 거예요.

일을 queue에 보내기만 하고 신경을 안쓰고 있는데.. 그럼 실제 해당 작업이 언제 끝나는지는 어떻게 알지?

Swift에서는 클로저를 통해 해당 시점을 알려줍니다. 이를 completionHandler 또는 completion 이라고 하는데 이건 나중에 더 자세히 알아보기로 해요~

동기 (sync)

좋아요.. 비동기를 이해했으면 동기는 그나마 수월할거예요. 바로 들어가 봅시다

자기만 일하는 사실에 화가 난 메인 스레드가 queue에 일부 작업들을 보내고 난 후 취할 수 있는 두번째 행동은 뭐였져?

끝날 때까지 기다린 후다음 라인 실행 한다

이게 바로 동기의 개념입니다.

어떤 작업을 queue에 보낸 뒤 신경끄고 냅다 다음 라인을 실행해버리는 async와는 다르게 queue에 보낸 작업이 완료 될 때까지 기다린 후 다음 줄로 넘어갑니다

코드로 봅시다

DispatchQueue.global().sync {
//task
}

이번에는 async가 아니라 sync로 보내고 있죠? 이 부분에 집중해서 해석해보자면

원래의 작업이 진행되고 있던 메인 스레드에서 global dispatch queue로 task를 보낸 후, 다음 라인 실행을 위해 해당 작업이 끝나기를 기다린다

가 되겠네요!

아까와 비슷한 코드를 봅시다. asyncsync로 바뀌었다는 점 주목해주세요!

윗 빗금에서 밑 빗금까지 main thread에서 실행하는데는 얼마나 걸릴까요?

정확히는 체크해봐야 알겠지만 6초보다는 좀 더 걸리겠다 까지는 감이 오시나요? 제가 돌려 봤을때는 약 6.0034초 정도 나오네요.

왜냐면 메인 스레드에서는 작업을 queue에 넘긴 후 해당 작업이 끝나고 나서야 다시 자기 할 일을 할테니까요!

“아니;;;; 기껏 큐로 보내놓고서 도대체 왜 기다리는거야; 그냥 메인 스레드에서 다 처리하는거랑 뭐가 다른데;;” 라는 생각이 드시나요? 맞아요 그래서 동기적으로 보내는 코드를 짜더라도 실질적으로는 메인쓰레드에서 일을 한다고 해요 ㅎ 대박적~

왜 비동기 처리가 필요한가

비동기로 처리했을때 좋아보였던 점은?! 당연히 시간 절약이겠죠~ 그리고 시간이 많이 드는 작업의 대부분은 서버와의 통신이기 때문에 네트워크와 관련된 작업들은 내부적으로 비동기적으로 구현이 되어있습니다.

이렇게 URLSession 으로 통신을 한다? 내부적으로 다른 스레드 사용 + 비동기로 구현이 되어 있는 걸 우리가 사용하고 있는거라구요..!!

네트워킹을 하면.. 비동기로 해야하는 것 같은데.. 나는 async를 명시적으로 쓴 적이 없는 것 같은데.. 혼란스럽다.. 라는 생각이 들곤 했는데! 맞아요 사실 우린 이미 내부적으로 구현된걸 사용하고 있던 거였음요 ㅎㅎ

마치며

오.. 3강까지 쓴 내 자신 칭찬해👏🏻👏🏻 글을 정리하면서 동기 비동기에 대한 개념을 더 잘 잡을 수 있는 것 같아요. 착각인가? ㅎ 이러고 삼십분 후면 또 까먹겠지만 그러면 다시 읽어보면 되겠죠 뭐~ 그럼 20000~!

이전 포스팅 👈🏻

다음 포스팅 👉🏻

출처

--

--