web-dev-qa-db-ja.com

global()。asyncのmain.syncはどういう意味ですか?

Swiftではこのようなパターンを時々使いました。

DispatchQueue.global().async {
    // do stuff in background, concurrent thread

    DispatchQueue.main.sync {
        // update UI
    }
}

このパターンの目的は明らかです。グローバルスレッドで時間のかかる計算を実行して、UIがロックされないようにし、計算が完了した後にメインスレッドでUIを更新します。

計算するものが何もない場合はどうなりますか?私のプロジェクトでロジックを見つけました

//A
DispatchQueue.main.sync {
    // do something
}

クラッシュするが

// B
DispatchQueue.global().async {
    DispatchQueue.main.sync {
        // do something
    }
}

クラッシュしません。

それらはどう違いますか?そして、ケース[〜#〜] b [〜#〜]はこれだけで異なりますか?

// C
DispatchQueue.main.async {
    // do something
}

そしてもう一つ質問。メインスレッドがシリアルキューであることはわかっていますが、複数のコードブロックを複数のmain.async、並行キューのように機能します。

DispatchQueue.main.async {
    // do A
}

DispatchQueue.main.async {
    // do B
}

メインスレッドが実際にシリアルキューである場合、どのようにして同時に実行できますか?メインスレッドがUIを更新できる以外に、グローバルコンカレントキューとどのように異なるのか、それが単なる時間スライスである場合はどうなりますか?

18
Ryan

x.syncは、呼び出しブロックが一時停止し、同期ブロックが続行するまで終了するまで待機することを意味します。だからあなたの例では:

DispatchQueue.global().async {
    // yada yada something
    DispatchQueue.main.sync {
        // update UI
    }
    // this will happen only after 'update UI' has finished executing
}

通常、メインにsyncを戻す必要はありません。おそらく、非同期はデッドロックを回避するのに十分で安全です。非同期タスクを続行する前に、メインで何かが終了するまで待つ必要がある特別な場合を除きます。

クラッシュの例のように-同期の呼び出しと現在のキューのターゲット設定はデッドロックです(呼び出しキューは同期ブロックが完了するのを待ちますが、ターゲットキュー(同じ)がsyncの呼び出しを待ってビジー状態であるため開始しません仕上げ)そしてそれがおそらくクラッシュの理由です。

非同期でメインキューの複数のブロックをスケジュールする場合について:それらは並列に実行されません-それらは次々に発生します。また、キュー==スレッドであると想定しないでください。複数のブロックを同じキューにスケジュールすると、システムが許す限り多くのスレッドが作成される可能性があります。メインキューだけが特別で、メインスレッドを利用します。

22
Mindaugas

キュー[もっと]

GCDには、主に3つのタイプのキューがあります。

1。メインキュー:はメインスレッドで実行され、シリアルキューです。
2。グローバルキュー:システム全体で共有される同時キュー優先度の異なる4つのキューがあります。高、デフォルト、低、バックグラウンドです。バックグラウンドプライオリティキューは最低のプライオリティを持ち、システムへの悪影響を最小限に抑えるために、あらゆるI/Oアクティビティで抑制されます。
3。カスタムキュー:シリアルまたは同時のユーザーが作成するキュー。これらのキュー内の要求は、実際にはグローバルキューの1つになります。

同期vs非同期

GCDでは、synchronouslyまたはasynchronouslyのいずれかでタスクをディスパッチできます。

synchronous関数は、タスクの完了後に呼び出し元に制御を返します。キューをブロックブロックし、タスクが完了するまで待機します。 DispatchQueue.sync(execute:)を呼び出すことにより、作業単位を同期的にスケジュールできます。

asynchronous関数はすぐに戻り、タスクの開始を命令しますが、タスクの完了を待機しません。したがって、非同期関数は、現在の実行スレッドが次の関数に進むのを妨げません。 DispatchQueue.async(execute:)を呼び出すことにより、作業単位を非同期にスケジュールできます。

まとめ

一般に、現在のスレッドをブロックせずにネットワークベースのタスクまたはCPUを集中的に使用するタスクをバックグラウンドで実行する必要がある場合は、asyncを使用します。

さまざまなキューをasyncでいつどのように使用するかについてのクイックガイドを次に示します。

  • メインキュー:これは、同時キューのタスクでの作業が完了した後にUIを更新する一般的な選択です。これを行うには、あるクロージャーを別のクロージャー内にコーディングします。メインキューをターゲットにしてasyncを呼び出すと、現在のメソッドが終了した後、この新しいタスクが実行されることが保証されます。
  • グローバルキュー:これは、非UI作業をバックグラウンドで実行するための一般的な選択です。
  • カスタムシリアルキュー:バックグラウンド作業を順次実行して追跡する場合に適しています。これにより、一度に1つのタスクしか実行されないことがわかっているため、リソースの競合や競合状態が解消されます。メソッドからのデータが必要な場合は、別のクロージャーを宣言してデータを取得するか、syncの使用を検討する必要があることに注意してください。

よくある間違い:

mainキューからDispatchQueue.main.syncを呼び出すと、ディスパッチされたブロックが完了するまでキュー(main)が待機するため、アプリはフリーズしますが、ディスパッチされたブロック)開始することさえできません(mainキューが停止して待機していたため)

一般的な非同期vs同期

ソースは here です

2
yoAlex5