並列処理を行うには、ディスパッチキュー、オペレーションキュー、Threadクラスの3種類の方法がある。
ディスパッチキュー、オペレーションキューはGrand Central Dispatch(GCD)って言うスレッドを管理する機能を使って実行する。ディスパッチキューはGCDをラップしただけのもの(と思う)で、オペレーションキューはより高機能にしたもの(と思う)だ。
Threadクラスは、まーマルチスレッドの基本的な機能を提供しているもので、ディスパッチキューやオペレーションキューの下働きを行っている。
ここでは、オペレーションキューを使う。
まずは、単純に別スレッドでなんか実行する。
// キューを用意する。
let queue = OperationQueue()
// キューに処理を追加する。
queue.addOperation {
// ↓ 時間のかかる処理の代わり
Thread.sleep(forTimeInterval: 10)
print("hoge1")
}
print("hoge2")
// キューにあるオペレーションが実行されて終わるのを待つ
// これはGUIアプリのメインスレッドでは使用しない方がいい
queue.waitUntilAllOperationsAreFinished()
print("END")
これを実行すると、こんな表示になる。
hoge2
hoge1
END
addOperationでキューに追加した処理が別スレッドで実行され、hoge2が表示されたあと、約10秒後、hoge1が表示される。
3つの処理を並列実行させてみる。
print(Thread.current.description)
// 3種類の処理(BlockOperation)を用意する。
let op1 = BlockOperation {
for i in 0..<10 {
Thread.sleep(forTimeInterval: 1.0)
print(Thread.current.description + ",op1,\(i)")
}
}
let op2 = BlockOperation {
for i in 0..<10 {
Thread.sleep(forTimeInterval: 1.0)
print(Thread.current.description + ",op2,\(i)")
}
}
let op3 = BlockOperation {
for i in 0..<10 {
Thread.sleep(forTimeInterval: 1.0)
print(Thread.current.description + ",op3,\(i)")
}
}
// // オペレーションの依存関係を設定
// // op1->op2->op3の順で実行されるようにする。
// // op2はop1が終わってから実行されるようにする。
// op2.addDependency(op1)
// // op3はop2が終わってから実行されるようにする。
// op3.addDependency(op2)
// キューを用意する。
let queue = OperationQueue()
// キューに処理を追加する。
queue.addOperation(op1)
queue.addOperation(op2)
queue.addOperation(op3)
// キューにあるオペレーションが実行されて終わるのを待つ
// これはGUIアプリのメインスレッドでは使用しない方がいい
queue.waitUntilAllOperationsAreFinished()
これを実行すると、3つの処理の表示が入り乱れてこんな感じに表示される。
<NSThread: 0x600000062c40>{number = 1, name = main}
<NSThread: 0x600000068280>{number = 2, name = (null)},op1,0
<NSThread: 0x60800046eac0>{number = 3, name = (null)},op3,0
<NSThread: 0x60800027ed00>{number = 4, name = (null)},op2,0
<NSThread: 0x60800046eac0>{number = 3, name = (null)},op3,1
<NSThread: 0x60800027ed00>{number = 4, name = (null)},op2,1
<NSThread: 0x600000068280>{number = 2, name = (null)},op1,1
<NSThread: 0x60800027ed00>{number = 4, name = (null)},op2,2
<NSThread: 0x60800046eac0>{number = 3, name = (null)},op3,2
<NSThread: 0x600000068280>{number = 2, name = (null)},op1,2
<NSThread: 0x60800027ed00>{number = 4, name = (null)},op2,3
<NSThread: 0x600000068280>{number = 2, name = (null)},op1,3
<NSThread: 0x60800046eac0>{number = 3, name = (null)},op3,3
<NSThread: 0x600000068280>{number = 2, name = (null)},op1,4
<NSThread: 0x60800046eac0>{number = 3, name = (null)},op3,4
<NSThread: 0x60800027ed00>{number = 4, name = (null)},op2,4
<NSThread: 0x60800027ed00>{number = 4, name = (null)},op2,5
<NSThread: 0x60800046eac0>{number = 3, name = (null)},op3,5
<NSThread: 0x600000068280>{number = 2, name = (null)},op1,5
<NSThread: 0x600000068280>{number = 2, name = (null)},op1,6
<NSThread: 0x60800046eac0>{number = 3, name = (null)},op3,6
<NSThread: 0x60800027ed00>{number = 4, name = (null)},op2,6
<NSThread: 0x60800046eac0>{number = 3, name = (null)},op3,7
<NSThread: 0x60800027ed00>{number = 4, name = (null)},op2,7
<NSThread: 0x600000068280>{number = 2, name = (null)},op1,7
<NSThread: 0x60800046eac0>{number = 3, name = (null)},op3,8
<NSThread: 0x600000068280>{number = 2, name = (null)},op1,8
<NSThread: 0x60800027ed00>{number = 4, name = (null)},op2,8
<NSThread: 0x60800027ed00>{number = 4, name = (null)},op2,9
<NSThread: 0x60800046eac0>{number = 3, name = (null)},op3,9
<NSThread: 0x600000068280>{number = 2, name = (null)},op1,9
ソースでコメントアウトしているコードで処理(オペレーション)の依存関係が設定できる。op2.addDependency(op1)でop1の処理が終わらないとop2が実行されないようになる。つまり、コメントアウトしている依存設定を有効にすると、op1の実行がおわってから、op2が実行され、op2が終わってからop3が実行される。
さて、並列処理では排他処理が必要になってくるんですが、それはまたの機会にw
コメント