동시성을 통해 애플리케이션의 여러 부분을 동시에 실행할 수 있습니다.
동시성은 앱의 다른 부분을 동시에 실행하는 데 도움이 됩니다.

시스템 수준에서 동시성을 구현하기 위해 스레드가 생성됩니다. CPU 코어는 주어진 시간 동안 스레드를 생성할 수 있습니다. 그러나 동시성을 구현하는 대가 또는 불이익은 스레드를 안전하게 유지하기 어렵다는 것입니다.
GCD

GCD는 Apple의 동시성 라이브러리로, 모든 iOS 장치에 대한 다중 스레드 코드를 만드는 데 도움이 됩니다.
디스패치 큐와 런 루프

디스패치 큐는 말 그대로 큐에 디스패치(제출)하는 것입니다. 디스패치할 것은 물론 작업(클로저 및 dispatchWorkItem)입니다. 이 distpatch 대기열은 스레드와 서비스를 가져옵니다. 스레드 작업을 마치면 해당 스레드를 자동으로 종료할 수 있습니다.
사용자는 스스로 스레드를 생성할 수 있습니다. 그리고 스레드에서 런 루프를 실행할 수 있습니다. 메인 스레드는 런 루프와 메인 큐를 모두 가질 수 있습니다.
디스패치 대기열에는 작업을 제출하는 두 가지 방법이 있습니다.
비동기 실행
첫 번째 방법은 비동기 실행입니다.

디스패치 큐에 여러 작업을 배치하고 스레드를 호출하여 작업을 처리합니다. 디스패치 큐는 큐에 있는 작업을 하나씩 처리합니다.

그런 다음 대기열의 작업이 완료되면 시스템이 스레드를 해제합니다.
동기식 실행

다시 말하지만, 위의 예와 같은 비동기 작업이 포함된 dipatch 대기열이 있습니다. 스레드에서 코드(작업)를 실행하고 대기열에서 이 작업이 완료될 때까지 대기하도록 하고 싶습니다. 해당 태스크가 디스패치 큐에 제출되면 해당 큐는 차단(대기 상태)되어 실행 요청된 항목이 완료될 때까지 대기합니다.

해당 대기열에 비동기 작업을 추가할 수 있으며 디스패치 대기열은 해당 작업을 처리할 스레드를 가져옵니다. 비동기 태스크가 실행된 후 동기화 태스크가 실행되어야 할 때 디스패치 큐는 대기 중인 스레드로 제어를 전송하고 태스크를 실행하며 디스패치 큐의 제어를 작업자 스레드로 가져옵니다.

나머지 작업도 대기열에서 처리된 다음 스레드가 해제됩니다.

그렇다면 메인 스레드에서 사용자 인터페이스 차단 작업(리소스가 많은 변환 작업)을 격리하려는 경우 다른 대기열에서 작업을 실행할 수 있습니다. 그러면 디스패치 대기열로 변환 작업을 지원할 수 있습니다. 이제 데이터를 변환하기 위해 변환할 데이터를 다른 큐에 생성된 변환 코드 블록으로 옮기고 변환한 후 다시 메인 쓰레드로 보낸다.
// Dispatch Queue 생성
let queue = DispatchQueue(label: "com.example.imagetransform")
// Dispatch Queue에 비동기 작업 제출
queue.async {
let smallImage = image.resize(to: rect)
// Dispatch main queue 로 메인 스레드에서 작업 실행
DispatchQueue.main.async {
imageView.image = smallImage
}
}
동시성 제어

애플리케이션에서 동시성을 제어해야 하는 경우가 있습니다. 디스패치(전체 GCD 라이브러리 참조)에서 사용하는 스레드 풀은 시스템의 모든 호출에서 사용하는 동시성을 제한합니다.
그러나 애플리케이션 또는 시스템 호출의 다른 부분이 작업자 스레드를 차단하는 경우 Dispatch는 코드 실행을 계속하기 위해 차단된 작업자 스레드에서 더 많은 작업자 스레드를 생성하여 동시성을 제공하려고 시도합니다.
따라서 코드를 실행하는 데 사용할 올바른 수의 디스패치 대기열을 선택해야 합니다. 그렇지 않으면 하나의 스레드를 차단하고, 다른 스레드를 생성하고, 다시 차단하고, 다른 스레드를 생성하는 패턴이 반복되어 스레드 폭발이 발생합니다.
(WWDC 2015 – GCD로 반응이 빠르고 효율적인 앱 구축 – https://kswift.21 참조)
애플리케이션 구조화

메인 스레드에서 다른 대기열로 작업을 가져오고 동시에 처리하는 것이 효율적이라는 것을 확인했습니다. 이것을 효과적으로 적용하는 방법은 무엇입니까?

이전 방법은 독립적인 데이터 흐름이 있는 애플리케이션의 영역을 식별하고 이를 하위 시스템으로 분리하고 디스패치 대기열로 지원했습니다. 각 하위 시스템에 대해 각 작업을 실행하기 위한 대기열이 제공됩니다. (체인)
또 다른 방법은 작업을 그룹화하고 해당 작업이 완료될 때까지 기다리는 것입니다. 하나의 항목이 다른 여러 작업을 생성하는 경우 이러한 작업이 완료될 때까지만 진행하고 싶다면 디스패치를 통해 구현할 수도 있습니다. (그룹화)
작업 그룹화

DispatchGroup은 작업을 추적하는 데 도움이 됩니다. 생성은 단순히 DispatchGroup 개체를 생성하는 문제입니다.
그리고 디스패치에 작업을 제출할 때 선택적 매개변수로 그룹을 추가할 수 있습니다. 다른 대기열에서 실행할 수 있지만 동일한 그룹과 연결됩니다. 그리고 그룹에 작업을 추가할 때마다 그룹은 작업에 카운터를 추가하여 완료를 기다립니다. 그리고 제출된 작업이 모두 완료되면 그룹은 알림을 통해 선택한 대기열에 완료를 알릴 수 있습니다.
작업은 순차적으로 실행되며 카운터는 작업이 완료될 때마다 감소합니다. 그리고 마지막 작업이 완료되면 그룹 프로세스는 알림 블록에서 알립니다.
하위 시스템 간 동기화
마지막 방법은 동기 실행을 통해 하위 시스템 간의 상태를 직렬화하는 것입니다.

이는 상호 배제(동기화) 속성을 사용할 수 있습니다. 이렇게 하면 작업이 대기열에 동기적으로 제출될 때 각 작업이 동시에 실행되지 않습니다.
이를 통해 간단한 스레드 안전 속성 액세스를 구축할 수 있습니다. 동기화 대기열을 호출하고 동기화 대기열에서 값을 캡처하고 반환합니다. 그러나 이로 인해 각 실행 시스템 간에 잠금 그래프가 발생합니다. 이로 인해 교착 상태가 발생할 여지가 있습니다.
서비스 품질 클래스 사용
WWDC 2015 – GCD로 반응이 빠르고 효율적인 앱 구축 에서 QoS에 대해 설명하였으므로 변경 사항에 대해서만 간략하게 설명합니다.

async 메서드에 QoS 매개변수를 추가하기만 하면 됩니다.
나중에 더 높은 QoS 작업을 제출하면 우선순위 역전을 해결할 수 있습니다. 해당 작업을 더 빠르게 실행하려면 디스패치 대기열에서 이전 작업의 QoS를 올리기만 하면 됩니다. 이는 작업을 더 빠르게 실행하는 데 도움이 된다는 의미가 아니라 제출된 작업과 함께 모든 이전 작업의 우선 순위를 지정한다는 의미입니다.
또한 특정 QoS 클래스의 디스패치 큐를 생성할 수 있습니다. 예를 들어 작업이 항상 백그라운드에서 실행되는 경우 해당 작업을 모두 실행하는 대기열을 만들 수 있습니다. 해당 대기열에 작업을 제출하면 해당 작업에 해당 QoS가 적용됩니다. 보다 세분화된 수준에서 디스패치 대기열에 대한 비동기 호출을 수행하면 호출 부분에서 실행 컨텍스트를 캡처합니다.
이에 대한 더 많은 제어를 위해 DispatchWorkItem을 생성하여 더 많은 제어가 가능한 작업 항목을 생성할 수 있습니다.

예를 들어, assignCurrentContext 플래그로 작업 항목을 생성한 경우 dipatch 대기열에 제출된 시간의 QoS가 아닌 생성된 시간을 중심으로 QoS를 가져옵니다. 제출 당시 생성된 시간의 속성으로 dipatch에 제출할 작업 항목을 생성할 수 있습니다.
또한 DispatchWorkItem의 wait 메서드를 사용하여 계속 진행하기 전에 작업을 완료해야 함을 dispatch에 알릴 수 있습니다. 대기 방식을 사용하면 태스크가 속한 큐에 대한 보류 중인 태스크 이전의 태스크가 실행될 큐의 QoS와 일치하도록 승격됩니다. 이를 통해 보류 중인 작업의 우선 순위에 따라 실행을 수행할 수 있습니다.
이는 DispatchWorkItem이 제출된 디스패치 큐를 알고 있기 때문에 가능합니다. Semaphore와 Groups를 사용하여 대기하는 경우에는 이 정보가 저장되지 않으므로 wait 메소드를 호출하더라도 Pending 작업 이전의 작업은 발생하지 않고 실행된다. , 보류 중인 작업이 이전 작업보다 먼저 실행된다는 보장이 없습니다.
(DispatchWorkItem에 대한 자세한 정보는 https://kswift.20에 정리되어 있습니다.)
동기화
Swift의 속성은 원자적이지 않기 때문에 게으른 속성을 동시에 초기화하면 아마도 두 번 호출될 것입니다. 그래서 동기화가 필요합니다.

동기화하는 것을 잊어버리면 앱이 충돌하거나 데이터가 엉망이 됩니다.
전통적으로 잠금은 동기화에 사용되었습니다. Swift에는 C 기반 잠금을 구현하는 구조체가 포함되어 있으므로 이를 확인할 수 있습니다.

그러나 Swift는 모든 것이 움직일 수 있다고 가정하므로 뮤텍스 및 잠금과 같은 기능이 작동하지 않을 수 있습니다. 따라서 Swift에서 이러한 종류의 전통적인 구조체 기반 C 잠금(pThread_mutex_t)을 사용하지 않는 것이 좋습니다.
움직일 수 있다는 개념(값에 의한 복사 vs 참조에 의한 복사)
소유권은 복사되어 메모리에서 전달되는 것이 아니라 메모리에서 전달되고 이동됩니다.
- 함수나 메서드 등에서 값을 반환할 때 반환 값을 복사하는 대신 이동할 수 있습니다.
- 이를 통해 한 변수에서 다른 변수로 값이 할당되더라도 값이 이동되기 때문에 메모리 사용량을 최소화하면서 값을 안전하게 공유할 수 있습니다.

기존 잠금을 사용하려면 클래스 기반 Foundation.Lock을 사용할 수 있습니다.
그러나 위에 표시된 것과 같이 Object-C에서 기본 클래스를 도입해야 합니다.
동기화에 GCD 사용

GCD를 통한 동기화는 기존 잠금을 사용하는 것과 비교하여 오용 가능성을 줄입니다. 코드는 범위가 지정된 방식으로 실행되기 때문에 실행이 완료되면 잠금이 자동으로 해제됩니다. 따라서 잠금 해제에 대해 걱정할 필요가 없습니다.
그리고 대기열은 실제로 XCode의 런타임 디버깅과 더 잘 통합됩니다.

동기화는 위와 같은 방식으로 구현할 수 있습니다.
전제 조건

이것은 주어진 대기열에 대한 코드에 불변이 있음을 나타냅니다. 현재 큐에서 실행 중인지 현재 큐에서 실행 중인지 여부를 나타내는 전제 조건입니다.
동시 세계의 개체 수명 주기

동기화가 필요한 일부 개체를 처리하는 방법
- 개체를 만들고 해당 속성을 설정합니다. -설정
- 개체 활성화 이 개체를 다른 하위 시스템에서 사용할 수 있도록 하는 것입니다. 이제 이 개체에는 더 많은 동시성 작업을 수행하는 성능 역할이 있습니다. -활성화
- 개체 무효화 이것은 모든 하위 시스템에 이 개체가 사라짐을 알리는 것입니다. -무효
- 개체가 파괴됨 -할당 취소
원천
https://developer.apple.com/videos/play/wwdc2016/720/?time=1070