0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【翻訳】Parallel Programming with Swift — Part 4/4

Posted at

この記事は、 Swift による並列プログラミングシリーズのパート4です。パート1では、 Dispatch Queue とシステムが提供するキューについて調べました。パート2では、タスクを定義する別の方法と、 GCD が提供する強力な API に焦点を当てました。パート3では、 Operation と Operation Queue について説明しました。今回は、オペレーションを作成し、オペレーション・キューに追加してみましょう。

このシリーズをすべてご覧になりたい方は、こちらをクリックしてください。

Concurrency & GCD — Parallel Programming with Swift — Part 1/4 (https://medium.com/swift-india/parallel-programming-with-swift-part-1-4-df7caac564ae)

GCD — Parallel Programming with Swift — Part 2/4 (https://medium.com/swift-india/parallel-programming-with-swift-part-2-4-46a3c6262359)

ブロック・オペレーション:

1つまたは複数のブロックの同時実行を管理するオペレーション。 BlockOperation クラスは Operation クラスを継承しています。このオブジェクトを使用すると、複数のブロックを同時に実行することができます。複数のブロックを実行する場合、全てのブロックの実行が終了して初めて Operation 自体が終了したとみなされます。

ブロック・オペレーションに追加されたブロックは、デフォルトの優先順位で適切な作業キューにディスパッチされます。

let queue = OperationQueue()

for i in 1...3 {
    let operation = BlockOperation()
    operation.addExecutionBlock {
        if !operation.isCancelled {
                print("###### Operation \(i) in progress ######")
                let imageURL = URL(string: "https://upload.wikimedia.org/wikipedia/commons/0/07/Huge_ball_at_Vilnius_center.jpg")!
                let _ = try! Data(contentsOf: imageURL)
                
                OperationQueue.main.addOperation {
                    print("Image \(i) downloaded...")
                }
        }
    }
    operation.queuePriority = .high
    queue.addOperation(operation)
}

queue.maxConcurrentOperationCount = 2
queue.waitUntilAllOperationsAreFinished()
queue.cancelAllOperations()

addDependency メソッドを使用することで、指定した operation の完了時に operation を実行することができます。

let queue = OperationQueue()

for i in 1...3 {
    let dependentOperation = BlockOperation()
    dependentOperation.addExecutionBlock {
        if !dependentOperation.isCancelled {
            print("###### Operation \(i) in progress ######")
            let imageURL = URL(string: "https://upload.wikimedia.org/wikipedia/commons/0/07/Huge_ball_at_Vilnius_center.jpg")!
            let _ = try! Data(contentsOf: imageURL)
            
            print("Image \(i) downloaded...")
        }
    }
    dependentOperation.queuePriority = .high
    
    let operation = BlockOperation {
        print("Execute Operation \(i), Once dependent work is done")
    }
    operation.addDependency(dependentOperation)
    queue.addOperation(operation)
    queue.addOperation(dependentOperation)
}

queue.maxConcurrentOperationCount = 2
queue.waitUntilAllOperationsAreFinished()
queue.cancelAllOperations()

NSInvocationOperation:

Objective C では NSInvocationOperation を作成できますが、 Swift では利用できません。

非同期オペレーション:

Operation クラスをサブクラス化することで、非同期オペレーションを作成することができます。

//  Created by Vasily Ulianov on 09.02.17, updated in 2019.
//  License: MIT
import Foundation

/// Subclass of `Operation` that adds support of asynchronous operations.
/// 1. Call `super.main()` when override `main` method.
/// 2. When operation is finished or cancelled set `state = .finished` or `finish()`
open class AsynchronousOperation: Operation {
    public override var isAsynchronous: Bool {
        return true
    }
    
    public override var isExecuting: Bool {
        return state == .executing
    }
    
    public override var isFinished: Bool {
        return state == .finished
    }
    
    public override func start() {
        if self.isCancelled {
            state = .finished
        } else {
            state = .ready
            main()
        }
    }
    
    open override func main() {
        if self.isCancelled {
            state = .finished
        } else {
            state = .executing
        }
    }
    
    public func finish() {
        state = .finished
    }
    
    // MARK: - State management
    
    public enum State: String {
        case ready = "Ready"
        case executing = "Executing"
        case finished = "Finished"
        fileprivate var keyPath: String { return "is" + self.rawValue }
    }
    
    /// Thread-safe computed state value
    public var state: State {
        get {
            stateQueue.sync {
                return stateStore
            }
        }
        set {
            let oldValue = state
            willChangeValue(forKey: state.keyPath)
            willChangeValue(forKey: newValue.keyPath)
            stateQueue.sync(flags: .barrier) {
                stateStore = newValue
            }
            didChangeValue(forKey: state.keyPath)
            didChangeValue(forKey: oldValue.keyPath)
        }
    }
    
    private let stateQueue = DispatchQueue(label: "AsynchronousOperation State Queue", attributes: .concurrent)
    
    /// Non thread-safe state storage, use only with locks
    private var stateStore: State = .ready
}

operation間のデータの受け渡し

operation 間でデータを受け渡すには、さまざまなアプローチがあります。主に採用されているのはアダプター・パターンです。ここでは、新しい BlockOperation を作成してデータを渡します。この記事では、全てのアプローチを分かりやすく紹介します。

Grand Central Dispatch より Operation を使用する利点

依存関係

Operation は、特定の順序でタスクを実行することを可能にする、 operation 間の依存関係を追加する API を提供します。Operationは、すべての依存関係の実行が終了した時点で準備完了となります。

Observable

Operation と OperationQueue には、 KVO を使用して観察できる多くのプロパティがあります。

operation の状態

オペレーションやオペレーション・キューの状態を監視できます。

制御

operation の一時停止、キャンセル、再開ができます。

最大同時動作できるキューの数

同時に実行できるオペレーションキューの最大数を指定できます。maxConcurrentOperationCount に 1 を指定することで、シリアルオペレーションキューを作成できます。

【翻訳元の記事】

Parallel Programming with Swift — Part 4/4
https://medium.com/swift-india/parallel-programming-with-swift-part-4-4-f3c8459cb017

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?