はりまや日記

なんか適当にいろいろ綴ったりなんかするところ

iphoneアプリ開発日記その7

処理の並列化を考える

下調べ

ios での並列化処理について調べてみた。
こんな感じ

名称 処理系 特徴
gcd c 最適化してくれる
NSOperation objc 最適化してくれる。gcdベース
pthread c リソース管理などを全部自前でやらなくては!
NSThread objc リソース管理などを全部自前でやらなくては!

今回は NSOperation で行こうと思います。
そんな性能いらないし。



さて、多分に漏れず NSOperation にも Blocks 化の波が来ています。
それを使いませう


使いそうな機能としてはこんなものです。

  • NSBlockOperation
    • +blockOperationWithBlock:^(void)block
      インスタンス生成時にタスクを追加する
    • -addExecutionBlock:^(void)block
      タスクを追加する
  • NSOperation
    • -setCompletionBlock^(void)block
      他のタスクが完了したときに実行する処理を追加
    • -addDependency: (NSOperation *)
      タスクの依存関係を追加
    • -start
      タスク実行

詳細はリファレンスで
ここ


で、実行は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 すると非同期になったりするのだろうか…ちょっと気になる
そのうち試してみよう
→ 試してみたけど駄目でした。 フラグだけ立てればいいってものでもないらしい