iphoneアプリ開発日記その7
処理の並列化を考える
下調べ
ios での並列化処理について調べてみた。
こんな感じ
名称 | 処理系 | 特徴 |
---|---|---|
gcd | c | 最適化してくれる |
NSOperation | objc | 最適化してくれる。gcdベース |
pthread | c | リソース管理などを全部自前でやらなくては! |
NSThread | objc | リソース管理などを全部自前でやらなくては! |
今回は NSOperation で行こうと思います。
そんな性能いらないし。
さて、多分に漏れず NSOperation にも Blocks 化の波が来ています。
それを使いませう
使いそうな機能としてはこんなものです。
- NSBlockOperation
- +blockOperationWithBlock:^(void)block
インスタンス生成時にタスクを追加する - -addExecutionBlock:^(void)block
タスクを追加する
- +blockOperationWithBlock:^(void)block
- NSOperation
- -setCompletionBlock^(void)block
他のタスクが完了したときに実行する処理を追加 - -addDependency: (NSOperation *)
タスクの依存関係を追加 - -start
タスク実行
- -setCompletionBlock^(void)block
詳細はリファレンスで
ここ
で、実行はstart でも出来るのですが、NSOperationQueue を使ってもできます。
単純なタスクなら NSBlockOperation で完結してもよさそう。
実験
というわけで、operation だけのやつと Queue 付きのやつを動かしてみよう
- (void)operationOnly{ NSBlockOperation * operation = NSBlockOperation.new; NSInteger sleepInterval = 2; for (int i = 0; i< 10; i++){ [operation addExecutionBlock:^{ [NSThread sleepForTimeInterval:sleepInterval]; NSLog(@"wakeup. i: %d, thread: %@", i, [NSThread currentThread]); }]; } [operation setCompletionBlock:^{NSLog(@"complete: %s", __func__ );}]; [operation start]; NSLog(@"done?"); } - (void)operationWithQueue { NSOperationQueue * queue = NSOperationQueue.new; NSBlockOperation * operation = NSBlockOperation.new; NSInteger sleepInterval = 2; for (int i = 0; i< 10; i++){ [operation addExecutionBlock:^{ [NSThread sleepForTimeInterval:sleepInterval]; NSLog(@"wakeup. i: %d, thread: %@", i, [NSThread currentThread]); }]; } [operation setCompletionBlock:^{NSLog(@"complete: %s", __func__ );}]; [queue addOperation:operation]; // [queue waitUntilAllOperationsAreFinished]; NSLog(@"done?"); }
NSOperationのみの結果
2013-06-08 01:26:10.217 NSOperationLesson[1039:12303] wakeup. i: 0, thread: <NSThread: 0x71488b0>{name = (null), num = 3} 2013-06-08 01:26:10.217 NSOperationLesson[1039:12c03] wakeup. i: 1, thread: <NSThread: 0x756a300>{name = (null), num = 4} 2013-06-08 01:26:10.217 NSOperationLesson[1039:11303] wakeup. i: 2, thread: <NSThread: 0x713dc00>{name = (null), num = 1} 2013-06-08 01:26:10.217 NSOperationLesson[1039:14c03] wakeup. i: 3, thread: <NSThread: 0x7642c80>{name = (null), num = 5} 2013-06-08 01:26:12.224 NSOperationLesson[1039:14c03] wakeup. i: 7, thread: <NSThread: 0x7642c80>{name = (null), num = 5} 2013-06-08 01:26:12.224 NSOperationLesson[1039:12c03] wakeup. i: 5, thread: <NSThread: 0x756a300>{name = (null), num = 4} 2013-06-08 01:26:12.224 NSOperationLesson[1039:12303] wakeup. i: 4, thread: <NSThread: 0x71488b0>{name = (null), num = 3} 2013-06-08 01:26:12.224 NSOperationLesson[1039:11303] wakeup. i: 6, thread: <NSThread: 0x713dc00>{name = (null), num = 1} 2013-06-08 01:26:14.228 NSOperationLesson[1039:14c03] wakeup. i: 8, thread: <NSThread: 0x7642c80>{name = (null), num = 5} 2013-06-08 01:26:14.228 NSOperationLesson[1039:12c03] wakeup. i: 9, thread: <NSThread: 0x756a300>{name = (null), num = 4} 2013-06-08 01:26:14.230 NSOperationLesson[1039:11303] done? 2013-06-08 01:26:14.230 NSOperationLesson[1039:12c03] complete: __31-[ViewController operationOnly]_block_invoke_2
Queue付きの結果
2013-06-08 01:27:23.384 NSOperationLesson[1063:11303] done? 2013-06-08 01:27:25.387 NSOperationLesson[1063:12c03] wakeup. i: 1, thread: <NSThread: 0x711fcb0>{name = (null), num = 6} 2013-06-08 01:27:25.387 NSOperationLesson[1063:14d03] wakeup. i: 3, thread: <NSThread: 0x7126ea0>{name = (null), num = 5} 2013-06-08 01:27:25.387 NSOperationLesson[1063:12303] wakeup. i: 0, thread: <NSThread: 0x750fb70>{name = (null), num = 4} 2013-06-08 01:27:25.387 NSOperationLesson[1063:12e03] wakeup. i: 2, thread: <NSThread: 0x8a1f7a0>{name = (null), num = 3} 2013-06-08 01:27:27.391 NSOperationLesson[1063:14d03] wakeup. i: 5, thread: <NSThread: 0x7126ea0>{name = (null), num = 5} 2013-06-08 01:27:27.391 NSOperationLesson[1063:12303] wakeup. i: 6, thread: <NSThread: 0x750fb70>{name = (null), num = 4} 2013-06-08 01:27:27.391 NSOperationLesson[1063:12e03] wakeup. i: 7, thread: <NSThread: 0x8a1f7a0>{name = (null), num = 3} 2013-06-08 01:27:27.391 NSOperationLesson[1063:12c03] wakeup. i: 4, thread: <NSThread: 0x711fcb0>{name = (null), num = 6} 2013-06-08 01:27:29.395 NSOperationLesson[1063:12303] wakeup. i: 9, thread: <NSThread: 0x750fb70>{name = (null), num = 4} 2013-06-08 01:27:29.395 NSOperationLesson[1063:14d03] wakeup. i: 8, thread: <NSThread: 0x7126ea0>{name = (null), num = 5} 2013-06-08 01:27:29.396 NSOperationLesson[1063:12303] complete: __36-[ViewController operationWithQueue]_block_invoke_2
お、ログの出方が違う。queue 付きの方は、すぐに最後のログが出ているので、非同期で動いているようだ。
operation のみの方は、start でタスクが終了するまで待ってる気がする。
試しに queue の方で wait をかけてみると、こうなった。
2013-06-08 01:30:48.278 NSOperationLesson[1091:12c03] wakeup. i: 2, thread: <NSThread: 0x751de40>{name = (null), num = 6} 2013-06-08 01:30:48.278 NSOperationLesson[1091:14a0f] wakeup. i: 0, thread: <NSThread: 0x760ff20>{name = (null), num = 4} 2013-06-08 01:30:48.278 NSOperationLesson[1091:12303] wakeup. i: 1, thread: <NSThread: 0x7153380>{name = (null), num = 5} 2013-06-08 01:30:48.278 NSOperationLesson[1091:14d03] wakeup. i: 3, thread: <NSThread: 0x90231d0>{name = (null), num = 3} 2013-06-08 01:30:50.284 NSOperationLesson[1091:14a0f] wakeup. i: 4, thread: <NSThread: 0x760ff20>{name = (null), num = 4} 2013-06-08 01:30:50.284 NSOperationLesson[1091:14d03] wakeup. i: 7, thread: <NSThread: 0x90231d0>{name = (null), num = 3} 2013-06-08 01:30:50.284 NSOperationLesson[1091:12c03] wakeup. i: 5, thread: <NSThread: 0x751de40>{name = (null), num = 6} 2013-06-08 01:30:50.284 NSOperationLesson[1091:12303] wakeup. i: 6, thread: <NSThread: 0x7153380>{name = (null), num = 5} 2013-06-08 01:30:52.288 NSOperationLesson[1091:14d03] wakeup. i: 9, thread: <NSThread: 0x90231d0>{name = (null), num = 3} 2013-06-08 01:30:52.288 NSOperationLesson[1091:14a0f] wakeup. i: 8, thread: <NSThread: 0x760ff20>{name = (null), num = 4} 2013-06-08 01:30:52.289 NSOperationLesson[1091:12c03] complete: __36-[ViewController operationWithQueue]_block_invoke_2 2013-06-08 01:30:52.291 NSOperationLesson[1091:11303] done?
ふむ、やはり start だと wait がかかってるようだ。
start を非同期にする方法はないのだろうか? そう思ってリファレンスを見ると、
start はデフォルトで non-concurrent で、concurrent にしたけりゃ start 以下4つのメソッドを実装しろとのこと。
しかも OSX10.6 では無視されるとか書いてあるので、queue を使うのがよさそう。
感想
isConcurrent を replace すると非同期になったりするのだろうか…ちょっと気になる
そのうち試してみよう
→ 試してみたけど駄目でした。 フラグだけ立てればいいってものでもないらしい