はい、専用のシリアル キューは、複数のスレッド間で共有されるリソースへのアクセスを同期する素晴らしい方法です。そして、はい、シリアル キューを使用すると、各タスクは前のタスクが完了するまで待機します。
2 つの観察:
これは非常に非効率的なプロセスのように思えますが、共有リソースの同時更新を最小限に抑えることを目標とする同期手法 (キューベースまたはロックベースのアプローチ) の中心にあるものです。
NSLock
ただし、多くのシナリオでは、単純なミューテックス ロック、または@synchronized
ディレクティブなどの他の一般的な手法よりも、シリアル キュー手法の方がパフォーマンスが大幅に向上します。代替の同期手法については、 「スレッド プログラミング ガイド」の「同期」セクションを参照してください。ロックの代わりにキューを使用する方法については、同時実行プログラミング ガイドの「スレッドからの移行」セクションの「ロック ベースのコードの削除」を参照してください。
シリアル キュー パターンのバリエーションとして、GCD 同時キューを作成する「リーダー/ライター」パターンを使用する方法があります。
queue = dispatch_queue_create("identifier", DISPATCH_QUEUE_CONCURRENT);
次に、 を使用して読み取りを実行しますdispatch_sync
が、 を使用して書き込みを実行しますdispatch_barrier_async
。最終的に効果的なのは、同時読み取り操作を許可することですが、書き込みが同時に実行されないようにすることです。
リソースで同時読み取りが許可されている場合、リーダー/ライター パターンにより、シリアル キューのパフォーマンスをさらに向上させることができます。
つまり、タスク #24 をタスク #23 まで待機させるのは効率が悪いように見えますが、これは、共有リソースの同時更新を最小限に抑えようとする同期手法に固有のものです。また、GCD シリアル キューは驚くほど効率的なメカニズムであり、多くの単純なロック メカニズムよりも優れていることがよくあります。リーダー/ライター パターンは、状況によっては、パフォーマンスをさらに向上させることができます。
以下の私の最初の回答は、「シリアル ディスパッチ キューは同時実行をどのように保証しますか?」というタイトルの混乱を招く元の質問への回答でした。振り返ってみると、これは間違った用語を誤って使用しただけです。
これは興味深い言葉の選択です。「シリアル ディスパッチ キューはどのようにして並行性を保証するのでしょうか?」
キューには、シリアル、コンカレント、およびメイン キューの3 つのタイプがあります。シリアル キューは、名前が示すように、前のブロックが終了するまで、次にディスパッチされたブロックを開始しません。(あなたの例を使用すると、これは、タスク23に時間がかかる場合、完了するまでタスク24を開始しないことを意味します。)これは重要な場合があります(たとえば、タスク24がタスク23の結果に依存している場合、または両方のタスク23および 24 が同じ共有リソースにアクセスしようとしています)。
これらのさまざまなディスパッチされたタスクを相互に同時に実行したい場合は、並行キューを使用します ( で取得したグローバル並行キューのいずれか、またはオプションを使用しdispatch_get_global_queue
て独自の並行キューを作成できます)。同時キューでは、ディスパッチされたタスクの多くが同時に実行される場合があります。同時キューの使用には注意が必要ですが (特に共有リソースの同期)、適切に実装するとパフォーマンスが大幅に向上します。dispatch_queue_create
DISPATCH_QUEUE_CONCURRENT
また、これら 2 つのアプローチの妥協点として、操作キューを使用できます。これは、両方を同時に実行できますが、設定することにより、キューで同時に実行される操作の数を制限することもできますmaxConcurrentOperationCount
。これを使用する典型的なシナリオは、バックグラウンド ネットワーク タスクを実行する場合で、5 つを超える同時ネットワーク リクエストを必要としない場合です。
詳細については、同時実行プログラミング ガイドを参照してください。