2017년 7월 20일 목요일

Swift3에서 GCD 사용(Grand Central Dispatch) @@ Swift3.0



GDC란?

Grand Central Dispatch는 줄여서 GCD라고 하는데, 강력한 도구이며 우리가 유용한 멀티쓰레드의 효과를 얻기 위해 사용하는 큐(queue)나 세마포어(semaphore)와 같은 저수준의 프레임워크를 제공합니다.


동기와 비동기

GCD는 큐(queue)는 처리할 부분에 대해 처리를 등록하여 알맞은 스레드에서 처리되는 것이지만 큐에 등록시 다음 실행방식 하나를 지정할 수 있다.
 - 동기화
큐에 처리를 등록한 스레드가 등록한 처리가 완료될때까지 대기
GCD메소드는 sync~
 - 비동기
큐에 처리를 등록한 스레드가 등록한 처리가 완료될 때까지 기다리지 않음
GCD메소드는 async~

차이점은 처리가 완료될 때까지 기다리냐 아니냐의 차이이다. 사실 실무적으로 sync는 사용방법을 잘못하면 스레드 교착상태에 빠질 수 있어 되도록 async를 사용하는 것을 추천한다.


큐 종류

Serial : 
처리를 직렬로 실행한다. 큐의 이전작업이 완료된 후, 다음작업을 시작한다. 한번에 수행할 작업은 하나뿐이다.

let SerialQueue = DispatchQueue(label:"queuename")

Concurrent :
처리를 병렬로 실행한다. 처리가 대기열에서 제거되는 순서는 FIFO이지만 한번에 여러작업을 실행하고 처리가 완료되는 차례도 제멋대로이다.

let ConcurrentQueue = DispatchQueue(label:"queuename", attributes : .concurrent)


*Swift3에서 기본으로 Serial를 사용하고 attributes값을 사용해서 Concurrent 로 만든다.

Main Queue 와 Global Queue

Main Queue
큐 중에서도 앱 시작시 시스템에 의해 자동으로 만들어지는 메인큐라는 별도의 큐가 있다. 이는 대기열에서 등록된 작업은 메인스레드에서 직렬로 실행된다. 이는 별도의 Serial queue라고 말할 수 있다.

DispatchQueue(label: "main").async {
  // async task
  DispatchQueue.main.async {
    print("main")
  }
}


DispatchQueue.main.async 통해 메인큐에서 작업 수행
이때 생성되는 것은 Serial queue인데 Concurrent queue를 생성하려면 아래와 같이 옵션을 지정한다.

DispatchQueue(label: "main", attributes: .concurrent)

Global Queue
글로벌큐는 큐 중에서도 특이점이 있는데, 글로벌 큐는 작업이 들어오면 즉시 스레드를 생성해서 처리한다. 들어오는 만큼 작업을 무한대로 멀티스레딩 한다는 의미이다. 하지만 다른 큐들은 한 번에 하나씩만 작업을 처리한다.

DispatchQueue.global(qos: .default).async {
  print("global")
}


DispatchQueue.global에서 얻을 수 있는 큐는 시스템에서 준비된 Concurrent queue이다. 인수로 지정한 qos(Quality of service)는 우선순위를 결정해준다. 여기서는 default로 지정했지만 우선순위가 높은 것부터 순서대로 아래와 같이 제공되고 있다.

userInteractive
: 유저 사용성을 위해 즉시 수행되는 타입.
UI갱신, 사용자 이벤트 처리 , 애니메이션 등에 사용

userInitiated
: 비동기 UI queue에서 수행되지만, 시스템의 다른 작업들보다 우선순위가 높게 수행된다.
일단 시작되면 끝나기 전에 다른 작업이 중간에 다시 시작될 일은 거의 없다. 빠르게 수행될 수 있고,
UI 상호 작용을 해야 하는 경우에 사용

default
:시스템에서 제공하는 Qos class 타입을 따르기 위해 사용하는 것으로 다른 qos 와 구분을 위해 정의된 것은 아니다.

utility
: 지속적인 작업이 필요할때 사용할 타입이다. 시스템에서 비교적 높은 레벨로 수행된다.
에너지 효율적으로 동작한다고 한다

background

: 시간에 민감하지 않은 작업들을 수행할때 사용된다. 언제 수행될지는 GCD가 컨트롤 한다.

unspecified


출처 : https://brunch.co.kr/@tilltue/29



특정시간 후 작업 수행

아래는 10초후 어떤 작업을 실행하는 예로 DispatchTime.now()에서 얻은 현재 시간에서 .seconds(10)을 통해 10초를 추가했다. seconds는 DispatchTimeInterval이라는 enum이며 다른 값으로는 miliseconds(밀리초), microseconds(마이크로초), nanoseconds(나노초)등으로 지정할 수 있다.

DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + .seconds(10)) {
  print("time")
}


Grouping

우선 그룹과 큐를 생성하고 큐에 처리를 등록할 때 그룹을 지정해서 큐와 그룹을 묶는다. 모든 큐 처리가 완료되면 메인스레드에서 처리된다.

//  dispatch 그룹 생성
let g = DispatchGroup()

let queue1 = DispatchQueue(label: "task1")
let queue2 = DispatchQueue(label: "task2")
let queue3 = DispatchQueue(label: "task3")

// 그룹에 포함 시키기
q1.async(group: g) {
  print("queue1 완료")
}
q2.async(group: g) {
  print("queue2 완료")
}
q3.async(group: g) {
  print("queue3 완료")
}
// 모든 queue 가 수행 된 뒤 g.notify 실행
g.notify(queue: DispatchQueue.main) {
  print("전체 작업완료")
}


DispatchWorkItem을 사용하여 작업실행

Swift 3에서 추가된 객체이다.
DispatchWorkItem은 작업을 캡슐화하는 클래스로 다음과 같이 큐 지정이 필수가 아니다. 이 경우 현재 컨텍스트(스레드)에서 처리된다. (실행을 컨트롤 할 수 있다.)

let wi = DispatchWorkItem {
 print("item")
}
wi.perform()


아래와 같이 큐를 지정도 할 수 있다.

q1.async(execute: wi)


이 DispatchWorkItem을 사용하면 처리 실행 perform()외에도 대기 wait() 및 취소 cancel()등 작업에 대한 제어를 세밀하게 할 수 있다. 그외 DisapatchWorkItemFlags옵션도 있어 QoS에 대한 상세한 실행도 가능하다.
중요한 것은 Objective-C언어에서 싱글톤 패턴을 구현하는데 사용하던 dispatch_once는 Swift 3.0에서는 사용할 수 없게 되었다. 또한 dispatch_once_t도 사용할 수 없게 되었다는 것을 기억하자.

Swift 3.0기반 싱글톤 패턴 구현


dispatch_once를 사용못하게 됨에 따라 Swift 3.0부터는 static let속성에서 제공된다. 이 말은 final에서 상속을 금지하고 이니셜라이저를 private하게 되어 자유롭게 인스턴스 생성을 금지하고 static let을 공개한 속성을 통해서만 유일한 인스턴스에 접근할 수 있다.


final class ClassSample {
  static let sharedInstance = ClassSample()

    private init() {

  }
}

출처 : https://swifter.kr/2016/10/22/swift-3-0%EA%B8%B0%EB%B0%98-gcd-%EA%B8%B0%EC%B4%88/





댓글 없음:

댓글 쓰기

추천 게시물

애플 개발자 등록방법 2016년 5월 8일 기준!!

애플 개발자 등록 절차 1. 개발자 등록 페이지 이동    애플 개발자 로그인 > Account 페이지 이동 > 하단 영역 클릭 (이미지 참조)   >> Enroll 클릭 >> 무조건 승인!! ...