GCDのDispatch Queue(シリアルキュー、コンカレントキュー、ホームキュー)

10904 ワード

まず歩く少年郎が書いた「iOSマルチスレッド--マルチスレッドを徹底的にマスターする『GCD』」に感謝します.それは私にGCDの多くの概念をはっきり理解させました.今は印象を深めるために、自分でもう1部ノートを書くつもりです.

1、キュー


キューは2種類のみです.
  • Serial Dispatch Queue(シリアルキュー):実行中の処理が終了するのを待って、次の処理を実行します.
  • Concurrent Dispatch Queue(コンカレントキュー):現在実行中の処理が終了するのを待たずに、次の処理を続行します.非同期実行でのみ、同時性を実現できます.
    シリアル・キューの作成:
    dispatch_queue_t serialQueue = dispatch_queue_create(" ", NULL);
    // 
    dispatch_queue_t serialQueue = dispatch_queue_create(" ", DISPATCH_QUQUE_SERIAL);
    

    同時キューの作成:
    dispatch_queue_t concurrentQueue = dispatch_queue_create(" ", DISPATCH_QUQUE_CONCURRENT);
    

    2、任務


    タスクを実行する方法は2つしかありません.
  • は同期して実行される.新しいスレッドを開かない
  • は非同期で実行されます.新しいスレッド
  • を開く
    同期実行:
    dispatch_sync(queue, ^{  ...  });
    

    非同期実行:
    dispatch_async(queue, ^{ ... });
    

    もう一つの違いは、同期キューは、タスクをキューに追加した後、すぐに実行することです.同時キューではありません.これは4,GCDの具体的な使用に反映される.

    3、GCDを使うのはキュー+タスク

  • シリアルキュー+同期実行
  • シリアルキュー+非同期実行
  • 同時キュー+同期実行
  • 同時キュー+非同期実行
  • ホームキュー+同期実行
  • ホームキュー+非同期実行
  • 補足:プライマリ・キューはシリアル・キューに属しますが、特殊性のため個別に列されます.

    4、GCDの具体的な使用


    (1)シリアルキュー+同期実行

    - (void) KSserialQueueSync {
        NSLog(@"test start");
        
        dispatch_queue_t serialQueue = dispatch_queue_create("com.ks.serialQueue", NULL);
        
        dispatch_sync(serialQueue, ^{
            for (int i = 0; i < 2; i++) {
                NSLog(@"block1 %@", [NSThread currentThread]);
            }
        });
        
        dispatch_sync(serialQueue, ^{
            for (int i = 0; i < 2; i++) {
                NSLog(@"block2 %@", [NSThread currentThread]);
            }
        });
        
        dispatch_sync(serialQueue, ^{
            for (int i = 0; i < 2; i++) {
                NSLog(@"block3 %@", [NSThread currentThread]);
            }
        });
        
        NSLog(@"test over");
    }
    
    [915:40526] test start
    [915:40526] block1 {number = 1, name = main}
    [915:40526] block1 {number = 1, name = main}
    [915:40526] block2 {number = 1, name = main}
    [915:40526] block2 {number = 1, name = main}
    [915:40526] block3 {number = 1, name = main}
    [915:40526] block3 {number = 1, name = main}
    [915:40526] test over
    

    出力結果分析:
  • は同期実行であるため、新しいスレッドは作成されず、メインスレッドで実行される.
  • はシリアルキューであるため、キューのタスクが次々と実行される.
  • すべてのタスクがtest starttest overの間で実行されるため、タスクがキューに入るとすぐに実行されることを示します.

  • (2)シリアルキュー+非同期実行

    - (void)KSserialQueueAsync {
        NSLog(@"test start");
        
        dispatch_queue_t serialQueue = dispatch_queue_create("com.ks.serialQueue", NULL);
        
        dispatch_async(serialQueue, ^{
            for (int i = 0; i < 2; i++) {
                NSLog(@"block1 %@", [NSThread currentThread]);
            }
        });
        
        dispatch_async(serialQueue, ^{
            for (int i = 0; i < 2; i++) {
                NSLog(@"block2 %@", [NSThread currentThread]);
            }
        });
        
        dispatch_async(serialQueue, ^{
            for (int i = 0; i < 2; i++) {
                NSLog(@"block3 %@", [NSThread currentThread]);
            }
        });
        
        NSLog(@"test over");
    }
    
    [941:46623] test start
    [941:46623] test over
    [941:46686] block1 {number = 2, name = (null)}
    [941:46686] block1 {number = 2, name = (null)}
    [941:46686] block2 {number = 2, name = (null)}
    [941:46686] block2 {number = 2, name = (null)}
    [941:46686] block3 {number = 2, name = (null)}
    [941:46686] block3 {number = 2, name = (null)}
    

    出力結果分析:
  • は非同期実行であるため、新しいスレッドが作成される.
  • はシリアルキューであるため、キュー内のタスクが次々と実行される.
  • は、すべてのキュータスクがtest startおよびtest overの後に実行されるため、タスクがキューに追加された直後に実行されるのではなく、すべてのタスクがキューに追加された後に実行されることを示す.

  • (3)同時キュー+同期実行

    - (void)KSconcurrentQueueSync {
        NSLog(@"test start");
        
        dispatch_queue_t concurrentQueue = dispatch_queue_create("com.ks.concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
        
        dispatch_sync(concurrentQueue, ^{
            for (int i = 0; i < 2; i++) {
                NSLog(@"block1 %@", [NSThread currentThread]);
            }
        });
        
        dispatch_sync(concurrentQueue, ^{
            for (int i = 0; i < 2; i++) {
                NSLog(@"block2 %@", [NSThread currentThread]);
            }
        });
        
        dispatch_sync(concurrentQueue, ^{
            for (int i = 0; i < 2; i++) {
                NSLog(@"block3 %@", [NSThread currentThread]);
            }
        });
        
        NSLog(@"test over");
    }
    
    [1001:58076] test start
    [1001:58076] block1 {number = 1, name = main}
    [1001:58076] block1 {number = 1, name = main}
    [1001:58076] block2 {number = 1, name = main}
    [1001:58076] block2 {number = 1, name = main}
    [1001:58076] block3 {number = 1, name = main}
    [1001:58076] block3 {number = 1, name = main}
    [1001:58076] test over
    

    出力結果分析:
  • 同期実行であるため、新しいスレッドは作成されず、メインスレッドで実行される.
  • はコンカレントキューであるが、同期実行であるため、コンカレント性は現れず、タスクは次々と実行される.
  • すべてのタスクがtest starttest overの間で実行されるため、タスクがキューに入るとすぐに実行されることを示します.

  • (4)同時キュー+非同期実行

    - (void)KSconcurrentQueueAsync {
        NSLog(@"test start");
        
        dispatch_queue_t concurrentQueue = dispatch_queue_create("com.ks.concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
        
        dispatch_async(concurrentQueue, ^{
            for (int i = 0; i < 2; i++) {
                NSLog(@"block1 %@", [NSThread currentThread]);
            }
        });
        
        dispatch_async(concurrentQueue, ^{
            for (int i = 0; i < 2; i++) {
                NSLog(@"block2 %@", [NSThread currentThread]);
            }
        });
        
        dispatch_async(concurrentQueue, ^{
            for (int i = 0; i < 2; i++) {
                NSLog(@"block3 %@", [NSThread currentThread]);
            }
        });
        
        NSLog(@"test over");
    }
    
    [1042:64557] test start
    [1042:64557] test over
    [1042:64615] block3 {number = 4, name = (null)}
    [1042:64618] block2 {number = 3, name = (null)}
    [1042:64640] block1 {number = 2, name = (null)}
    [1042:64615] block3 {number = 4, name = (null)}
    [1042:64618] block2 {number = 3, name = (null)}
    [1042:64640] block1 {number = 2, name = (null)}
    

    出力結果分析:
  • 非同期実行のため、新しいスレッドが作成されました.
  • 同時キューのため、非同期実行時にその同時性が現れ、タスク間で交互に同時に実行される.
  • は、すべてのキュータスクがtest startおよびtest overの後に実行されるため、タスクがキューに追加された直後に実行されるのではなく、すべてのタスクがキューに追加された後に実行されることを示す.

  • (5)メインキュー+同期実行

    - (void)KSmainQueueSync {
        NSLog(@"test start");
        
        dispatch_queue_t mainQueue = dispatch_get_main_queue();
        
        dispatch_sync(mainQueue, ^{
            for (int i = 0; i < 2; i++) {
                NSLog(@"block1 %@", [NSThread currentThread]);
            }
        });
        
        dispatch_sync(mainQueue, ^{
            for (int i = 0; i < 2; i++) {
                NSLog(@"block2 %@", [NSThread currentThread]);
            }
        });
        
        dispatch_sync(mainQueue, ^{
            for (int i = 0; i < 2; i++) {
                NSLog(@"block3 %@", [NSThread currentThread]);
            }
        });
        
        NSLog(@"test over");
    }
    
    [1084:70872] test start
    

    出力結果分析:
  • は1つの文しか出力されず、その後の文は実行されません.
  • プライマリ・キューは、プライマリ・スレッドのキューです.
  • デッドロック発生:同期実行は、すぐに実行されることを知っています(シリアルキュー同期実行と同時キュー同期実行の結果分析第3条を参照).しかし、現在のメインスレッドが実行しているタスクはKSmainQueueSyncというメソッドなので、このメソッドの実行が完了するのを待つ必要があります.しかし、KSmainQueueSyncこの方法は、最初の2番目の3番目のタスクが完了するのを待つ.互いに待ち合ってデッドロックを起こす.

  • 別のスレッドで呼び出せばいいので、シリアルキュー+非同期実行で新しいスレッドを作成します.
    dispatch_queue_t queue = dispatch_queue_create("com.ks.serialQueue", NULL);
        
    dispatch_async(queue, ^{
            [self KSmainQueueSync];
    });
    
    [1097:77638] test start
    [1097:77593] block1 {number = 1, name = main}
    [1097:77593] block1 {number = 1, name = main}
    [1097:77593] block2 {number = 1, name = main}
    [1097:77593] block2 {number = 1, name = main}
    [1097:77593] block3 {number = 1, name = main}
    [1097:77593] block3 {number = 1, name = main}
    [1097:77638] test over
    

    出力結果解析:プライマリ・キューはシリアル・キューの一種であるため、シリアル・キューの解析にも適用されます.
  • は同期実行であるため、新しいスレッドは作成されず、メインスレッドで実行される.
  • はシリアルキューであるため、キューのタスクが次々と実行される.
  • すべてのタスクがtest starttest overの間で実行されるため、タスクがキューに入るとすぐに実行されることを示します.

  • (6)主行列+非同期実行

    - (void)KSmainQueueAsync {
        NSLog(@"test start");
        
        dispatch_queue_t mainQueue = dispatch_get_main_queue();
        
        dispatch_async(mainQueue, ^{
            for (int i = 0; i < 2; i++) {
                NSLog(@"block1 %@", [NSThread currentThread]);
            }
        });
        
        dispatch_async(mainQueue, ^{
            for (int i = 0; i < 2; i++) {
                NSLog(@"block2 %@", [NSThread currentThread]);
            }
        });
        
        dispatch_async(mainQueue, ^{
            for (int i = 0; i < 2; i++) {
                NSLog(@"block3 %@", [NSThread currentThread]);
            }
        });
        
        NSLog(@"test over");
    }
    
    [1130:84261] test start
    [1130:84261] test over
    [1130:84261] block1 {number = 1, name = main}
    [1130:84261] block1 {number = 1, name = main}
    [1130:84261] block2 {number = 1, name = main}
    [1130:84261] block2 {number = 1, name = main}
    [1130:84261] block3 {number = 1, name = main}
    [1130:84261] block3 {number = 1, name = main}
    

    出力結果分析:
  • は非同期実行であり、新しいスレッドを開くことができるが、プライマリ・キュー列であるため、プライマリ・スレッドでのみ実行される.(この点は通常のシリアルキューとは異なる)
  • メインキューは特殊なシリアルキューであるため、キューのタスクは次々と実行される.
  • は、すべてのキュータスクがtest startおよびtest overの後に実行されるため、タスクがキューに追加された直後に実行されるのではなく、すべてのタスクがキューに追加された後に実行されることを示す.

  • (1)キューを作成することとスレッドを作成することは2つあります.(2)1つのスレッド内に複数のキューがあり,シリアルキューとパラレルキューが混在している可能性がある.(3)キューが同期実行であるか非同期実行であるかによって、新しいスレッドを作成するかどうか.(4)デッドロックの問題.