GCDのシリアルキューとパラレルキューおよびdispatch_group

7251 ワード

iOS_マルチスレッド技術


1.
NSThread各NSThreadオブジェクトは1つのスレッドに対応しており、軽量レベル(真のマルチスレッド)
2.次の2つの点は、アップルが開発した「同時」技術であり、プログラマーがスレッドの具体的な使用問題に関心を持たなくてもよい.
1>NSOperation/NSOperationQueueオブジェクト向けスレッド技術
2>GCD-Grand Central Dispatch(ディスパッチ)はC言語ベースのフレームワークで、マルチコアを活用できる、アップルが推奨するマルチスレッド技術です
 
以上の3つのプログラミング方式は上から下へ、抽象度階層は低から高へ、抽象度が高いほど使用が簡単で、Appleが最も推奨しているもので、プロジェクトでは多くのフレームワーク技術が異なるマルチスレッド技術を使用しています.                 
GCD_Grand Central Dispatch
GCDの全称Grand Central Dispatchはアップル社が提供したマルチコア特性を利用できるAPIである.コードを書いてキューに割り当てるだけで、システムが実行します.任意のコードを非同期または同期で実行できます.GCDはiOS 4にあります.0+を使用することができ、NSThread、NSOperationに代わる効率的で強力なテクノロジーです.
Dispatch queue_スケジューリングキュー(dispatch_queue)
スレッドに似ていますが、より簡単に使用できます.詳細を重視する必要はありません.
GCDのすべてのスケジューリングキューは、先頭の先頭のキューであるため、キューに追加されたタスクの開始順序と同じである.独立して実行するタスクの一部をキューに追加し、システム管理によって実行することができます.
キュー・タイプは全部で3種類あります.
≪連続キュー|Continue|emdw≫:各キューは、割り当てられた順序に従ってタスクを実行します.タスクを並列に操作する任意の数のキューを作成できます.
コンカレントキュー:コンカレントキューごとに1つ以上のタスクを同時に実行できます.タスクはキューに割り当てられた順序に従って実行を開始する.連続キューを作成することはできません.システムが提供する3つのキューから1つを選択して使用するしかありません.
   
メインキュー(シリアルキューとも呼ばれる):アプリケーション内の整列したメインキュー列であり、アプリケーションのメインスレッドタスクを実行する.
Dispatch queue_スケジュールキューの作成
1>シリアルキューのカスタマイズ、同期タスクの発行
 // 、 
    dispatch_queue_t queue = dispatch_queue_create("queueName", DISPATCH_QUEUE_SERIAL);
    
    dispatch_sync(queue, ^{
        //code  
    });
    dispatch_sync(queue, ^{
        //code  
    });

キュー内のタスクは同期して列挙され、タスクが実行されるとタスク2が実行されます.このタイプのタスクはプライマリ・スレッドと同期しており、プライマリ・スレッドがブロックされます.
  • カスタムシリアルキュー、非同期タスクのコミット
    // 、 
        dispatch_queue_t queue = dispatch_queue_create("queueName", DISPATCH_QUEUE_SERIAL);
        
        dispatch_async(queue, ^{
            //code  
        });
        
        dispatch_async(queue, ^{
            //code  
        });
    

    キューのタスクは同期して列を出し、タスクが実行されるとタスク2が実行されます.このタイプのタスクはプライマリ・スレッドと同時実行され、プライマリ・スレッドはブロックされません.
    2>パラレルキューのカスタマイズ、同期タスクの発行
    //  、 
        dispatch_queue_t queue = dispatch_queue_create("queueName", DISPATCH_QUEUE_CONCURRENT);
        dispatch_async(queue, ^{
            //code  
        });
        dispatch_async(queue, ^{
            //code  
        });
    

    キューのタスクは非同期の列で、タスクの列の順序は先進的な先出の順序で実行され、タスクが列を出した後、タスクが列を出してからタスクが列を出して(タスクがタスクと2に同期している)、メインスレッドと同期して、メインスレッド
  • をブロックします.
    パラレルキューのカスタマイズ、非同期タスクのコミット
    // 、 
        dispatch_queue_t queue = dispatch_queue_create("queueName", DISPATCH_QUEUE_CONCURRENT);
        dispatch_async(queue, ^{
            //code  
        });
        dispatch_async(queue, ^{
            //code  
        });
    

    タスクが一列になってからタスクが二列になってから、各タスク間は非同期で、メインスレッドをブロックしません.
    3>同期タスクをプライマリ・キューに送信(シリアル・キューでもある)
    // 
        dispatch_sync(dispatch_get_main_queue(), ^{
            //code
        });
    

    ブロック主スレッドプライマリ・キュー列で非同期タスクをコミット
    // 
        dispatch_async(dispatch_get_main_queue(), ^{
            //code 
        });
    

    4>グローバルキューでの同期タスクの発行(同時キューでもある)
     // 
     dispatch_sync(dispatch_get_global_queue(0, 0), ^{
         //code
     });
    

    グローバルキューで非同期タスクをコミット
  • // 
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            //code
        });
    

       dispatch_get_gloabal_Queueの1番目のパラメータは列挙タイプ(デフォルトは0)で、タスクの優先度を決定し、2番目のパラメータはApple保留パラメータ、伝0#define DISPATCH_QUEUE_PRIORITY_HIGH        2 #define DISPATCH_QUEUE_PRIORITY_DEFAULT     0 #define DISPATCH_QUEUE_PRIORITY_LOW         (-2) #define DISPATCH_QUEUE_PRIORITY_BACKGROUND  INT16_MIN(バックグラウンドタスク、優先度が最も低い)Dispatch Queuesの生成には、次のような方法があります.dispatch_queue_t queue = dispatch_queue_create("com.dispatch.serial", DISPATCH_QUEUE_SERIAL); //キュー内のblockは、実際には単一スレッドで実行される先進的なリードアウト(FIFO)の順序で実行されるシリアルキューを生成します.最初のパラメータはキューの名前で、デバッグ時に非常に役立ちます.できるだけ名前を変更しないでください.     2. dispatch_queue_t queue = dispatch_queue_create("com.dispatch.concurrent", DISPATCH_QUEUE_CONCURRENT);//同時実行キューを生成し、blockは複数のスレッドに配布されて実行する.dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);//プログラムプロセスでデフォルトで生成された同時キューを取得し、優先度を設定して高、中、低の3つの優先度キューを選択します.システムのデフォルトで生成されているため、dispatch_を呼び出すことはできません.resume()とdispatch_suspend()は、実行の継続または中断を制御する.3つのキューは3つのスレッドを表すものではなく、より多くのスレッドがある可能性があることに注意してください.コンカレントキューは、実際の状況に応じて合理的なスレッド数を自動的に生成することができ、dispatchキューがプログラムロジックに対して透過的なスレッドプールの管理を実現することも理解できる.公式サイトのドキュメントでは、3つの同時キューがあると説明されていますが、実際にはDISPATCH_に優先度を設定するより低いキューがあります.QUEUE_PRIORITY_BACKGROUND.Xcodeデバッグでは、使用中の各dispatchキューが観察されます. 4. dispatch_queue_t queue = dispatch_get_main_queue();//メインスレッドを取得するdispatchキューは、実際にはシリアルキューです.メインスレッドdispatchキューの実行の継続または中断も制御できません.dispatch_の使用asyncまたはdispatch_sync関数は、実行するblockをロードします.  dispatch_async(queue,^{//block具体コード});//非同期でblockを実行し、関数は直ちにdispatch_に戻るsync(queue,^{//block具体コード});//blockを同期して実行し、関数は返さず、blockが実行されるまで待つ.コンパイラは実際の状況に応じてコードを最適化するので、blockは実際には現在のスレッドで実行されており、新しいスレッドを生成する必要はありません.実際のプログラミングの経験は、dispatchの使用をできるだけ避けることを教えてくれた.syncは、ネストされた使用時にプログラムのデッドロックを引き起こしやすい.queue 1がシリアルキューである場合、このコードはすぐにデッドロックを生成します:dispatch_sync(queue1, ^{       dispatch_sync(queue1, ^{       ......    });        ......     }); 実際の運用では、一般的にdispatchで書くことができ、一般的なネットワーク要求データマルチスレッド実行モデル:dispatch_async(dispatch_get_global_queue(DISPATCH_QUE_PRIORITY_DEFAULT,0),^{//サブスレッドでネットワークリクエストデータを開始//データモデルdispatch_syncの更新(dispatch_get_main_queue(),^{//メインスレッドでUIコードを更新});    }); プログラムのバックグラウンド実行とUI更新コードがコンパクトで、コードロジックが一目瞭然です.dispatchキューはスレッドが安全で、シリアルキューを利用してロックの機能を実現することができます.例えば、マルチスレッドが同じデータベースを書く場合、書き込みの順序と書き込みごとの完全性を維持する必要があり、シリアルキューを簡単に利用すれば実現できます:dispatch_queue_t queue1 = dispatch_queue_create("com.dispatch.writedb", DISPATCH_QUEUE_SERIAL);      - (void)writeDB:(NSData *)data      {     dispatch_async(queue1, ^{      //write database    }); }次の呼び出しwriteDB:前回の呼び出しが完了するまで待たなければなりません.writeDB:メソッドはスレッドが安全であることを保証します.dispatchキューは、void dispatch_を含む他の一般的な関数も実装する.apply(size_t iterations, dispatch_queue_t queue, void (^block)(size_t));//blockを繰り返し実行するには、この方法は同期して返すこと、すなわち、すべてのblockが実行されるまで戻ること、非同期で返す必要がある場合はdispatch_にネストされることに注意してください.asyncで使用します.複数のblockの実行が同時またはシリアルで実行されるかどうかもqueueの同時またはシリアルに依存する.     void dispatch_barrier_async(dispatch_queue_t queue, dispatch_block_t block);//この関数は、キューに参加する前のblockが実行されるまで、同期実行のblockを設定できます.その後キューのblockに参加すると、このblockの実行が完了するまで実行が開始されません.     void dispatch_barrier_sync(dispatch_queue_t queue, dispatch_block_t block);//同様に、同期戻り関数void dispatch_である以外はafter(dispatch_time_t when, dispatch_queue_t queue, dispatch_block_t block);//blockの実行を遅らせて最後にdispatchキューの特色のある関数を見てみましょう:void dispatch_set_target_queue(dispatch_object_t object, dispatch_queue_t queue); 実行する必要があるタスク・オブジェクトを異なるキューに指定して処理します.このタスク・オブジェクトはdispatchキューでもdispatchソースでも構いません(後述します).また、このプロセスは動的であってもよく、キューの動的スケジューリング管理などを実現することができる.たとえば、2つのキューdispatchAとdispatchBがある場合、dispatchAはdispatchB:dispatch_に割り当てられます.set_target_queue(dispatchA, dispatchB); では、dispatchAでまだ実行されていないblockはdispatchBで実行されます.このときdispatchA運転を一時停止した場合:dispatch_suspend(dispatchA); dispatchA上の元のblockの実行を一時停止するだけで、dispatchBのblockは影響を受けません.一方、dispatchBの運転を一時停止すると、dispatchAの運転は一時停止されます.

  • GCD_要約キューのタイプは、キュー・タスクの実行方法を決定します(プライマリ・キューはシリアル・キューです).一般に、プライマリ・スレッドをブロックするタスクは非同期パラレル・キューにコミットされます.