Swift 3에서의 동기화 처리 (배타 제어)의 기본

이전에, 다음의 중얼거렸습니다만, 비교적 낡은 방법을 이용하고 있는 코드가 산견되기 때문에, Swift 3에서의 동기 처리(배타 제어)에 대해 정리해 보겠습니다.

getter는 sync에서 Swift 같은 락이 되어도 좋지만( ´・‿・`) htps // t. 코 / X2 rjyBmH7 — mono( ´・‿・`)🐶🍎📱⌚️ (@_mono) htps // t. 코 / 77 ~ ↑ GLj


참고 : August 7, 2016

과거의 방법



WWDC 슬라이드의 pp.120-123에 실려 있으므로 봐 주세요.

Concurrent Programming With GCD in Swift 3 - WWDC 2016 - Videos - Apple Developer



WWDC에서 권장하는 DispatchQueue.sync를 사용하는 방법



기본적으로 여기가 좋은 것 같습니다. 사실, 취급도 간단합니다.
class Account {
    private var _balance: Int = 0
    // デフォルトは、シリアルキュー
    private let lockQueue = DispatchQueue(label: "Account lock serial queue")
    // attributesに.concurrentを指定すると並行処理されるキューとなり同期処理の用途には不適切
//    private let queue = DispatchQueue(label: "", attributes: .concurrent)

    var balance: Int {
        // getterを同期処理に
        // クロージャー内で返した型をgetterの戻り値として返せる
        get {
            return lockQueue.sync { _balance }
        }
        // setterを同期処理に
        set {
            lockQueue.sync { _balance = newValue }
        }
    }

    // _balanceの増減操作をするには読み取りと書き込みをセットで括る必要あり
    func add(_ value: Int) {
        lockQueue.sync { _balance += value }
    }
}

포인트는 다음과 같습니다.
  • 시리얼 큐 (lockQueue 필드)를 작성해, 그것을 동기 처리에 사용한다
  • lockQueue.sync로 처리를 묶는 것만으로 동기 처리 할 수있다

  • 또, sync 메소드는, 몇개의 오버로드가 있어, 반환값을 돌려줄 수도 있어, 위의 예에서는 balance 의 get 의 반환값 없는 쪽이 사용되고 있습니다.
    public func sync(execute block: () -> Swift.Void)
    public func sync<T>(execute work: () throws -> T) rethrows -> T rethrows -> T
    

    간단하게 테스트해 보면, 무사히 배타 제어되고 있는 것을 확인할 수 있습니다.
    (아래 예에서는 balanceget
    let account = Account()
    
    for i in 0..<1_000 {
        DispatchQueue.global().async {
            account.add(10)
            // 次のように同期処理を介さず操作すると最終結果がズレる(低くなる)
            //account.balance += 10
        }
    }
    
    Thread.sleep(forTimeInterval: 1)
    print("final balance: \(account.balance)") // 10 x 1_000 = 10_000
    

    그러나 성능은 좋지 않다.



    퍼포먼스는 로우 레벨의 락 기법에 비해 나쁜 것 같습니다만, 안전・간단하므로, 그 근처가 아무래도 신경이 쓰이는 처리 이외는, Apple 추천의 set 를 사용하는 것이 좋을까라고 생각하고 있습니다.
  • Mutexes and closure capture in Swift

  • 혹은, DispatchQueue.sync 에서는 요건 채울 수 없을 때도, 로우 레벨의 다른 방법을 사용할 필요가 되어 온다고 생각합니다.

    좋은 웹페이지 즐겨찾기