티스토리 뷰

TIL

[TIL] 2022 / 09 / 02 (GCD)

희철 2022. 9. 2. 15:30

Concurrency Programming을 하기 위해서 몇 가지의 방법이 있음.

 

1. GCD

2. OperationQueue -> GCD로 작업을 일시중단하거나 재개하는데에서 한계가 있었기에 생김

3. Async/Await

 

오늘은 GCD에 대해서 알아보았음.

-> 나중에 따로 정리를 해야됨

 

 

GCD(Grand Central Dispatch)

 

 

DispatchQueue에는 네 가지의 케이스가 있음.

(디스패치는 보내는 것을 의미하므로 큐에 보내는 방식이라고 생각하면 될듯)

 

 

1. Serial / Sync

 

 

Serial은 메인 스레드를 의미함.

 

위의 코드를 설명하자면

 

메인스레드가 101...200까지 프린트하는 작업을 메인스레드에 넘기는 것임.

 

근데 메인스레드는 넘긴 작업이 끝날때까지 기다려야함.

-> sync이기때문에 동기적으로 진행되기때문. 즉, 이전 작업이 끝나야 다음 작업을 진행한다는 의미

 

지금 메인스레드는 1부터 100까지 출력한 뒤, 101부터 200까지 출력하는 구문을 본인에게 넘겼는데, 본인에게 넘긴 101부터 200까지 출력 구문이 끝날때까지 기다려야한다?

-> 무한대기 상태에 빠짐.

 

이를 교착상태 또는 데드락이라고 함.

 

이 코드는 사용할 일이 없으므로 main에 sync가 붙어있는 것은 가볍게 무시.

 

 

2. Serial / Async

 

 

1번과 같이 메인스레드에 넘겨주는 것은 똑같지만 비동기적으로 처리한다는 의미.

 

즉, 넘겨준 1부터 100까지 프린트하는 구문이 끝나지 않더라도 다음 작업을 진행한다는거임.

 

하지만 넘겨준 작업도 언젠간 자신이 해야되는거임.

 

그래서 넘기자마자 101부터 출력하는 구문을 실행한 뒤, 1부터 출력하는 코드를 실행하게될것임.

 

만약 for문은 밖에 있고 print부분만 DispatchQueue로 감싸져있다면 뭐가 다를까.

 

반복문이 진행될때마다 프린트 구문을 넘겨줌.

-> 큐에는 1을 출력하는 코드부터 계속 쌓이는거임. 

 

결론은 똑같음. 다만 태스크가 하나야 100개냐의 차이일뿐.

 

 

3. Concurrent(Global) / Sync

 

 

이제 main이 아닌 global을 사용하므로 다른 스레드로 작업을 넘긴다는 의미

 

근데 작업을 넘기지만 sync이므로 메인스레드는 작업이 끝날때까지 기다리게됨.

 

즉, 결국 메인스레드에서 혼자 작업하는거랑 똑같은거임

 

실제로 이렇게 코드가 작성되면 내부에서 그냥 메인스레드에서 실행한다고함.

 

결론은 굳이 쓸 이유가 없음.

 

 

4. Conccurent / Async

 

 

이제는 다른 스레드에게 작업을 보냄과 동시에 다음 작업을 실행할 수 있음.

 

따라서 위의 코드는

 

START가 출력되고 프린트 함수가 다른 스레드로 넘겨졌음.

 

동시에 101부터 출력이 시작됨.

 

따라서 전부 뒤섞여서 나올거임

 

하나씩 다른 스레드에서 실행되므로 안섞일 수가 없는거임.

 

 

네 가지 경우 중 두 가지 케이스만 사용하게될거임

 

두번째는 보통 UI를 만질 때 사용하고, 네번째는 네트워크 통신을 진행할 때 사용함

 

 

 

QOS(Quality Of Service)

 

 

DispatchQueue에서 global을 보면 괄호를 볼 수 있음.

 

qos매개변수를 통해 우선순위도 정할 수 있음.

 

우선순위 키워드에는 다섯 가지가 있음.

 

userInteractive

-> 가장 우선순위가 높아, UI와 관련된 작업을 할 때 사용.

 

userInitiate

-> 작업이 끝날때까지 유저가 인터랙션 할 수 없으므로, 사용자가 하고 있는 일에 대한 즉각적인 결과를 제공하거나 사용자가 앱을 사용하지 못하게 하는 작업에 사용. 

 

defaults

-> 빈 괄호일 때처럼 기본으로 설정되는 값. 우선순위 중간

 

utility

-> 사용자의 앱 사용을 방해하지 않는 작업에 사용. 

 

background

-> 우선순위가 가장 낮음. 주로 데이터 불러오기 등에 사용

 

참고해야 할 것은 우선순위가 빠른 작업이 끝나야 우선순위 낮은 작업이 실행되는 것이 아님.

 

 

CustomQueue

 

커스텀큐를 따로 만들 수도 있음

 

없는 우선순위를 만드는 것은 아니고 어떤 작업을 하는지 명시하고 싶을때 만들면 될듯.

 

 

 

DispatchGroup

 

 

난 이게 맘에듦.

 

기존에 네트워크 통신을 통해 데이터를 가져와서 뷰에 표시할 때 한 번에 표시되지 않는게 굉장히 맘에 안들었음.

 

근데 DispatchGroup을 쓰면 해결할 수 있음.

 

DispatchGroup 인스턴스를 생성해주고 async의 group으로 만들어둔 인스턴스를 넣어 하나의 그룹으로 만들어줄 수 있음.

 

그리고 그룹 내의 작업들이 다 끝난 것을 notify를 통해 알려줌.

 

보통 DispatchGroup을 이용하는 작업들은 UI와 관련한 작업들이기때문에 main을 쓴다고함.

 

당연히 그룹 안의 작업들은 순서대로 실행되지 않을 것임.

 

순서와 상관없이 세 가지 작업이 모두 끝나면 노티파이의 코드가 실행될 것임.

 

 

근데 네트워크 통신 작업을 그룹에서 해보니 제대로 출력되지않고 그냥 하는거랑 차이가 없었음.

 

이유는 그룹 안에 있더라도 네트워크 통신 내부의 코드들도 비동기적으로 실행되기때문에 새로운 스레드에 작업을 넘겨서 진행하기 때문

그래서 위와 같이 코드를 구성하면 그룹 내에 다 들어가있긴하지만 그룹과 관련없는 스레드로 작업을 보내버리기때문에 바로 끝나는 것으로 여겨져 계획한대로 실행되지 않음.

 

이를 해결하기위해 enter와 leave가 필요함.

 

코드가 시작되기 전에는 enter로, 끝났을 때는 leave로 노티파이에  알려줌.

그래서 위의 코드처럼 함수가 시작될때 enter를 호출하고, 끝났을때(컴플리션 핸들러에서 작성하면 작업이 마무리되고 실행됨) leave를 호출함.

 

이렇게 되면 다른 스레드로 보내는거와 관련없이 작업이 마무리된 것을 안 뒤에 노티파이가 알게될거임.

 

따라서 세 개의 이미지뷰들을 이미지가 동시에 바뀔 수 있음.

 

 

그룹 내에 동기적으로 동작하는 코드가 있다면 첫 번째 방법처럼 진행해도됨. 

 

하지만 네트워크 통신같은 작업이 있다면 아래처럼 enter와 leave를 이용해야 원하는대로 값을 얻을 수 있음.

 

 

 

 

RaceCondition

 

 

위의 코드는 그룹으로 이름을 바꾸는 코드를 묶은 것.

 

동기적인 코드이기때문에 문제가 없음.

 

세 코드가 끝나면 노티파이가 알게되어 결과를 출력할 것임.

 

근데 어떤 값이 올지 모름.

 

세 코드가 동시에 공유자원에 접근하고 있음.

 

이런 경우에 racecondition이 발생하는 것임

 

위와 같은 코드에서는 원하는 값이 딱 있는 것이 아니기에 당장은 큰 문제가 없겠지만, 연산을 생각해보겠음.

 

값을 연산하는 코드를 위와 같이 비동기적으로 실행한다고 생각해보면 공유자원의 값을 계속 비동기적으로 바꾸는 것임

 

그러다보면 분명 값이 잘못 계산되는 상황이 생길 것임.

 

 

'TIL' 카테고리의 다른 글

[TIL] 2022 / 09 / 06  (0) 2022.09.06
[TIL] 2022 / 09 / 05  (0) 2022.09.05
[TIL] 2022 / 08 / 31  (0) 2022.08.31
[TIL] 2022 / 08 / 29  (0) 2022.08.29
[TIL] 2022 / 08 / 27  (0) 2022.08.28
댓글
최근에 올라온 글
Total
Today
Yesterday