본문 바로가기

iOS/WWDC

[WWDC 2016] Currency Programming Guide (2/2)

Currency Programming Guide (1/2)

Currency Programming Guide (2/2)

 

WWDC 2016 Concurrent Programming With GCD in Swift 3 를 정리한 포스트입니다.

더 자세한 내용을 원하시면 위 링크를 참조하시길 바랍니다.

Choosing a Quality of Service

 

코드가 다른 CPU 우선 순위, 다른 IO 스케줄링 우선 순위로 실행된다.

 

 

Using Quality of Service Classes

QoS 품질에 따라 우선순위를 제어할 수 있다

dispatch queue 에서 비동기화(async) 가 실행되면 실행 컨텍스트가 캡쳐된다.

 

DispatchWorkItem

DispatchWorkItem allocateCurrentContext 옵션을 사용하면 DispatchQueue에 Submit 하는 시간이 아닌 실행 컨텍스트의 QoS가 사용된다.

 

Waiting for Work Items

DispatchWorkItem의 wait를 사용하여 신호를 보낼 수 있다.

Swift 3 and Synchronization

Synchronization is not part of the language in Swift 3 (Swift 3에서 동기화는 언어의 일부가 아닙니다.)

 

글로벌 변수는 Atomic(원자적)으로 초기화. 

글로벌 변수는 프로그램 실행되면서 동시에 메모리에 할당되기 때문에 당연히 원자적이다.

클래스, lazy 속성은 Atomic(원자적)이지 않다.

원자적이지 않다는 말은 초기화 컨텍스트를 실행하는 2개 이상의 다른 명령에서 동시에 두 번 생성(실행)될 수 있다는 것을 의미

 

 

 

Traditional C Locks in Swift

동기화 지점을 잊어버리면 앱 사용자의 데이터가 충돌하거나 손상되기 때문에 주의해야 한다.

sanitizer 는 앱에서 적절한 동기화가 누락된 위치를 파악하는 데 도움이 되는 도구이다.

 

동기화를 위해 전통적으로 C 의 lock 을 사용할 수 있다.

 

 

Correct Use of Traditional Locks

Objc-C 에서 전통적으로 Lock을 사용하는 방법은 Foundation.Lock 이다.

 

동기화를 위해 Lock 을 사용하는 것보다  DispatchQueue을 사용하는 것이 좋다.

 

첫 번째: 오용하기가 훨씬 쉽다.

두 번째: 디버깅 도구에서 Xcode의 실행 시간과 훨씬 더 잘 통합되어 있다.

 

 

Use Explicit Synchronization

Getter

동기화를 통해 이 내부 상태를 반환하면 상호배제를 할 수 있다.

 

Setter

Object Lifecycle in a Concurrent World 4단계

Setup

객체를 생성하고 객체를 사용할 수 있도록 필요한 속성을 부여하는 것

 

Activate

다른 하위 시스템에 알 수 있도록 하는 것

 

invalidation

모든 서브시스템은 객체가 deallocated을 알고 있는지 확인하는 것

 

Deallocation

Observer Pattern

위 4단계를 앱을 예를 들어 설명합니다.

데이터 변환 서브시스템이 작업을 수행하기 시작하면 사용자에게 시각적 표시를 제공할 수 있도록 서브시스템에서 상태 변화를 관찰할 수 있다.

 

데이터 변환 하위 시스템이 작업을 중지하면 시각적 표시가 사라짐

 

BusyController - Setup

Setup 은 Code, Animation 속성을 설정하는 단계

 

 

BusyController - Activation

 

Main Thread에서 상태 수신, 상태 변경 통지를 받기는 것을 등록한다.

상태가 수신되면 systemStarted(...) systemDone(...) 에 UI를 구현한다.

 

BusyController - Deallocation

deinit 함수에서 상태 수신 알림을 해제하는 것은 좋은 방법이 아니다.

 

deinit 함수에서 상태 수신 알림을 해제가 좋지 않은 이유

BusyController의 reference count는 2가 된다. (UI, Observers)

 

Main Thread가 가지고 있는 참조를 제거 할 때 여전히 하나(Data subsystem)가 남아있으므로 deinit이 실행되지 않는다.

 

 

DeadLock

weak 키워드를 이용하면 Reference Count 증가하지 않으므로 위에 문제를 해결 할 수 있다.

 

UI 의 참조를 제거하면 그림상 Octopus 는 BusyController에 대한 참조를 없앨 것이다.
DeadLock 의 문제 발생한다.

 

Explicit Invalidation

deinit 에서 알림 수신 객체를 취소하면 안된다.

명시적인 invalidate 함수를 호출해서 해결할 수 있는 방법이 있다.

그것은 Main Thread 에서 실행되는 것을 보장되어야 한다.

 

하지만 데이터 변환 서브시스템이 여전히 상태 전환을 전송하고 있으며, 무효화 시에도 DeadLock 이 일부 발생할 수 있습니다.

 

invalidated Bool로 invalidate 를 추적하고 invalidate 값이 true 일 경우에만 UI 를 업데이트 하도록 실행한다.

 

 

 

참조:

https://developer.apple.com/videos/play/wwdc2016/720

https://zeddios.tistory.com/509

https://hcn1519.github.io/articles/2018-07/gcddispatchqueue

https://developer.apple.com/library/archive/documentation/General/Conceptual/ConcurrencyProgrammingGuide/Introduction/Introduction.html#//apple_ref/doc/uid/TP40008091