dispatch_asyncについて


233

このコードについて質問があります

dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    NSData* data = [NSData dataWithContentsOfURL: 
      kLatestKivaLoansURL];
    [self performSelectorOnMainThread:@selector(fetchedData:) 
      withObject:data waitUntilDone:YES];
});

このコードの最初のパラメーターは

dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) 

このコードに、特定の優先度レベルのグローバル同時キューを返すことが定義されているグローバルキューでシリアルタスクを実行するように要求していますか?

dispatch_get_global_queueメインキューよりも使用する利点は何ですか?

私は混乱しています。これをよりよく理解するために私を助けていただけませんか。


1
コードを数行に分割して、よりわかりやすくする必要があります。dispatch_get_global_queue変数型の内部を安全にしますdispatch_queue_t myQueuemyQueueだけを `` dispatch_async`に渡して読みやすくする
Alex Cio

回答:


517

メインキューでデフォルトキューを使用する主な理由は、タスクをバックグラウンドで実行するためです。

たとえば、インターネットからファイルをダウンロードしていて、ダウンロードの進行時にユーザーを更新したい場合、優先度のデフォルトキューでダウンロードを実行し、メインキューのUIを非同期で更新します。

dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
    //Background Thread
    dispatch_async(dispatch_get_main_queue(), ^(void){
        //Run UI Updates
    });
});

私は私の質問はこれすなわちを行うためのロジックを理解するために多くの周りだったが、あなたの答えのためのデビッドのおかげで同時キューそのものであるグローバルキュー上のシリアルタスクを実行するには、このコードを求めていることを理解
user2332873は

私はあなたの提案を正確に行っていますが、UI更新の実行で[self.tableView reloadData]を呼び出しても、uiTableViewCellがすぐに更新されません。約4〜5秒かかります。 。
GrandSteph

@GrandSteph私はその方法に慣れていません。たぶん、そのメソッドの実行には5秒しかかかりません。dispatch_asyncの重要な点は、メインスレッドを停止せずにバックグラウンドで実行できることです。
David

2
何を0意味しますか?
ハニー、

3
@Honey 0はflagsパラメータで、現在はまったく何もしません。ドキュメントから:Flags that are reserved for future use. Always specify 0 for this parameter.
David

199

DISPATCH_QUEUE_PRIORITY_Xキューはすべて並行キューであり(一度に複数のタスクを実行できることを意味します)、特定のキュー内のタスクが「先入れ先出し」の順序で実行を開始するという意味でFIFOです。これは、シリアルキューであるメインキュー(dispatch_get_main_queue()から)と比較されます(タスクは、受け取った順に実行を開始し、実行を終了します)。

したがって、1000個のdispatch_async()ブロックをDISPATCH_QUEUE_PRIORITY_DEFAULTに送信すると、それらのタスクは、キューに送信した順序で実行を開始します。同様に、HIGH、LOW、およびBackgroundキューの場合。これらのキューに送信したものはすべて、メインアプリケーションスレッドとは別の代替スレッドのバックグラウンドで実行されます。したがって、これらのキューは、バックグラウンドダウンロード、圧縮、計算などのタスクの実行に適しています。

実行順序は、キューごとにFIFOであることに注意してください。したがって、1000個のdispatch_async()タスクを4つの異なる同時キューに送信し、それらを均等に分割して、Background、LOW、DEFAULT、HIGHの順に送信すると(つまり、HIGHキューで最後の250タスクをスケジュールする)、これらのタスクがCPUにできるだけ早く到達する必要があるというシステムの影響を受けているため、最初に表示される最初のタスクはそのHIGHキューにあります。

また、「順番に実行を開始します」とも言いますが、並行キューは、各タスクの時間の長さによっては、必ずしも順番に実行が終了するとは限らないことに注意してください。

アップルによると:

https://developer.apple.com/library/content/documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues/OperationQueues.html

並行ディスパッチキューは、並行して実行できる複数のタスクがある場合に便利です。並行キューは、先入れ先出しの順序でタスクをデキューするという点で、依然としてキューです。ただし、並行キューは、前のタスクが完了する前に追加のタスクをデキューする場合があります。任意の時点で並行キューによって実行される実際のタスク数は可変であり、アプリケーションの条件が変化すると動的に変化する可能性があります。使用可能なコアの数、他のプロセスによって実行されている作業の量、他のシリアルディスパッチキュー内のタスクの数と優先順位など、多くの要因が同時キューによって実行されるタスクの数に影響します。

基本的に、これらの1000個のdispatch_async()ブロックをDEFAULT、HIGH、LOW、またはBackgroundキューに送信すると、それらはすべて送信順に実行を開始します。ただし、短いタスクは長いタスクの前に終了する場合があります。これの背後にある理由は、利用可能なCPUコアがあるか、現在のキュータスクが計算上非集中的な作業を実行している(システムがコア数に関係なく追加のタスクを並行してディスパッチできると考えさせる)場合です。

並行性のレベルはシステムによって完全に処理され、システムの負荷およびその他の内部的に決定された要素に基づいています。これがGrand Central Dispatch(dispatch_async()システム)の優れた点です。ワークユニットをコードブロックとして作成し、(選択したキューに基づいて)作業ユニットに優先度を設定し、残りをシステムに処理させるだけです。

だからあなたの上の質問に答える:あなたは部分的に正しいです。指定された優先度レベルでグローバル並行キューで並行タスクを実行するように「そのコードに要求」している。ブロック内のコードはバックグラウンドで実行され、追加の(同様の)コードは、使用可能なリソースに対するシステムの評価に応じて、並列で実行される可能性があります。

一方、(dispatch_get_main_queue()からの)「メイン」キューは、シリアルキューです(同時ではありません)。メインキューに送信されたタスクは常に順番に実行され、常に順番に終了します。これらのタスクはUIスレッドでも実行されるため、進捗メッセージや完了通知などでUIを更新するのに適しています。


+1ですが、実際には、同時キューがFIFOであるか、単にランダムな順序であるかは問題ではないと思います。ループで5つのタスクを開始する場合、それらは本質的に同時に開始すると想定します。たとえば、同じコードを実行しても、最初のタスクの最初のI / O操作が5番目のタスクの前に発生するという保証はありません。OTOH、シリアルキューの場合、FIFOの動作は不可欠であり、IMHOは2つのキュータイプの違いを定義しています。
Gerhard Wesp 2015

信じられないほどの説明。たくさん拍手!
Okhan Okbay

36

Swiftバージョン

これは、DavidのObjective-C回答のSwiftバージョンです。グローバルキューを使用してバックグラウンドで実行し、メインキューを使用してUIを更新します。

DispatchQueue.global(qos: .background).async {
    
    // Background Thread
    
    DispatchQueue.main.async {
        // Run UI Updates
    }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.