GCDにおけるシリアル・パラレルとasync・syncの違い

3328 ワード

 * author:conowen@                                                                                                                            
 * E-mail:[email protected]      

キューは1つ以上のタスクで構成され、これらのタスクが実行を開始すると、スレッドに割り当てられて実行されます.
シリアル・キュー、パラレル・キュー
GCDプログラミングでは、キューコードを次のように作成します.
dispatch_queue_t queue_t_concurrent = dispatch_queue_create("com.conowen.concurrent", DISPATCH_QUEUE_CONCURRENT);//concurrent  
dispatch_queue_t queue_t_serial = dispatch_queue_create("com.conowen.serial", DISPATCH_QUEUE_SERIAL);//serial  

DISPATCH_QUEUE_SERIALの値はNULL
[タスクA,タスクB,タスクC,タスクD]がシリアルキューに順番に置かれて実行されると,最終的に結果が得られる順番もABCDの順番であり,パラレルキューで実行されると結果の順番はランダムである.
async、sync
async
dispatch_の使用asyncはブロックを呼び出します.例えば、dispatch_async(myQueue,myBlock);というmyBlockはmyQueueキューのキューの最後に置かれて実行を待っています.このmyBlockタスクはシリアルとパラレルではありません.myQueueがパラレルであれば、このmyBlockタスクはパラレルで、myQueueがシリアルキューであれば、このMyBlockはシリアルで実行されますが、dispatch_asyncはすぐに終わり、戻ります.
dispatch_async(myQueue, ^{   
  //do something
});


sync
dispatch_の使用syncは、dispatch_sync(myQueue,myBlock);のようにmyBlockタスクをmyQueueの上に置いて実行しますが、dispatch_syncはこのmyBlockの実行が完了するまで待機します.つまり、現在のdispatch_をブロックし続けます.syncが存在するスレッドはmyQueueキュー内のmyBlockタスクが実行されるまで戻ります.
キューとスレッドの関係
iOSには、シリアル・キュー、コンカレント・キュー、グローバル・キュー(パラレル)、プライマリ・キュー(シリアル)が一般的です.
まず、プライマリ・スレッド・キュー(シリアル)について説明します.同期または非同期にかかわらず、プライマリ・スレッドでのみ実行されます.
  • 同期(sync)非同期でタスクを開始すると、シリアルでもパラレルでも新しいスレッドは作成されず、Blockは現在のスレッドでのみ実行されます.
  • 非同期(async)非同期でタスクを開始すると、シリアルでもパラレルでも新しいスレッドが開きます.違いは、シリアルキューがスレッドを開くことです.パラレルキューは、複数のスレッド
  • を開く.
    同期(sync)の場合、プライマリ・スレッド・キュー(シリアル)が送信されますが、現在のスレッドがプライマリ・スレッドでない場合、Blockのタスクはプライマリ・スレッドのみで、現在のスレッドではありません.
    GCDテクノロジーを使用してマルチスレッドを実装すると、GCDはスレッドのライフサイクル(スレッドの作成、タスクのスケジュール、スレッドの破棄)を自動的に管理します.
    クラシックなデッドロック問題
    
    - (void)viewDidLoad
    {
        [super viewDidLoad];
        NSLog(@"1");
        dispatch_sync(dispatch_get_main_queue(), ^{
            NSLog(@"2");
        });
        NSLog(@"3");
    }
    
    ^{NSLog(@"2");}というBlockはdispatch_get_main_queue()のメインシリアルキューで実行されるが、シリアルキューであるため、Blockはすぐに実行されるわけではないので、dispatch_syncはメインスレッドをブロックし、main_queue// のBlockの実行が完了するのを待つが、メインスレッドがブロックされているため、Blockのコードは永遠に実行されず、これによるデッドロックとなる.
    syncシリアルキュー
    上のプライマリ・スレッドのデッドロックの問題はsyncがシリアル・キューで実行されていることです(プライマリ・スレッドはシリアル・キューです)
    syncパラレルキュー
    ただし、次のコードであればデッドロックは発生しません.
    dispatch_queue_t queue_t_concurrent = dispatch_queue_create("com.conowen.concurrent", DISPATCH_QUEUE_CONCURRENT);//concurrent
        dispatch_async(queue_t_concurrent, ^{
            dispatch_sync(queue_t_concurrent, ^{
                NSLog(@"2");
            });
        });
    

    Blockはパラレルキュー(キューに並ばなくてもよい)ですぐに実行され、結果が返されるため、dispatch_syncはBlock結果をずっと待っている状態が現れるのを待つことはなく、デッドロックは発生しません.
    だからアップルはdispatch_get_current_queueの方法を廃棄しました.以下のコードがデッドロックになるのを恐れています.
    
    dispatch_queue_t queue_t_serial = dispatch_queue_create("com.conowen.serial", DISPATCH_QUEUE_SERIAL);//serial  
        dispatch_async(queue_t_serial, ^{
            dispatch_sync(dispatch_get_current_queue(), ^{
                NSLog(@"0");
            });
        });