いものやま。

雑多な知識の寄せ集め

Swiftでの並列プログラミングについて調べてみた。(まとめ)

これまでの各記事は、以下から。

オペレーションキューとオペレーションオブジェクト

並列処理を行うには、オペレーションキューを用意して、そこに処理をオブジェクト化したオペレーションオブジェクトを追加する。

オブジェクトの生成と実行

// Foundationのインポートが必要。
import Foundation

// オペレーションキューを生成。
let queue = NSOperationQueue()

// オペレーションオブジェクトを生成。
// Swiftの場合、クロージャを使うといい。
let operation = NSBlockOperation {
  // 並列で行いたい処理
}

// オペレーションキューにオペレーションオブジェクトを追加すると、
// 処理が並列で行われる。
queue.addOperation(operation)

排他制御

オペレーションキューが同時に実行できる処理の最大数を指定することが出来る。
これを1にすれば、そのオペレーションキューに追加された処理は、同時には最大1つしか実行されないので、排他制御が出来る。

// 同時に実行できる処理の最大数を1にする。
queue.maxConcurrentOperationCount = 1

処理の同期

キューが空になるのを待ったり、処理が終了するのを待ったりすることも出来る。

// キューが空になるのを待つ
queue.waitUntilAllOperationsAreFinished()

// 処理が終了するのを待つ
operation.waitUntilFinished()

メインキューと実行ループ

メインスレッドに関連付けられたメインキューを使うことも出来る。
ただし、その場合、メインスレッドで実行ループが回っていないといけない。
メインキューに追加された処理は、同時に最大1つまでしか実行されないので、排他制御にも使える。

// メインキューを取得
let mainQueue = NSOperationQueue.mainQueue()

// メインスレッドで実行ループを回す
NSRunLoop.mainRunLoop().run()

依存関係の設定

処理間に依存関係を設定すると、依存する処理が終わってからでないと処理が開始されなくなる。

let opA = NSBlockOperation { /* 処理A */ }
let opB = NSBlockOperation { /* 処理B */ }

// 処理Bを行うより前に、処理Aを行う必要があるとする。
// (つまり、処理Bは処理Aに依存している)
// その場合、依存関係を追加する。
opB.addDependency(opA)

処理のキャンセル

処理のキャンセルを行うことも出来る。
ただし、キャンセルされる処理がキャンセルに対応している必要がある。

let operation = NSBlockOperation {}
operation.addExecutionBlock {
  [unowned operation] in
  // 何か処理

  // キャンセルされたかどうかをチェックする。
  // キャンセルされていれば、処理を終了する。
  if operation.cancelled {
    return
  }
  
  // 何か処理
}
queue.addOperation(operation)

// 処理をキャンセルする。
operation.cancel()

ディスパッチキュー

ディスパッチキューにブロックを追加すると、追加された順にブロックが実行されていく。

昨日の記事がほぼまとめなので、以下を参照。

今日はここまで!