DispatchQueue.main.asyncとDispatchQueue.main.syncの違い


99

DispatchQueue.main.asyncUI関連の操作に長年使っています。



Swiftはとの両方DispatchQueue.main.asyncを提供しDispatchQueue.main.sync、どちらもメインキューで実行されます。



誰かがそれらの違いを教えてくれますか?それぞれをいつ使用すればよいですか?



DispatchQueue.main.async {
    self.imageView.image = imageView
    self.lbltitle.text = ""

}

DispatchQueue.main.sync {
    self.imageView.image = imageView
    self.lbltitle.text = ""
}

回答:


46

これを使用するasyncと、ディスパッチされたブロックが実行されるまで待機せずに、呼び出し側のキューを移動できます。逆syncに、呼び出しキューを停止し、ブロックでディスパッチした作業が完了するまで待機します。したがってsync、デッドロックにつながる可能性があります。DispatchQueue.main.syncメインキューから実行してみてください。ディスパッチされたブロックが終了するまで呼び出しキューが待機するため、アプリはフリーズしますが、開始することさえできません(キューが停止して待機しているため)。

いつ使用するのsyncですか?DIFFERENTキューで何かが行われるのを待って、現在のキューで作業を続ける必要がある場合

同期の使用例:

シリアルキューではsync、ミューテックスとして使用して、保護されたコードを同時に実行できるスレッドが1つだけであることを確認できます。


DispatchQueue.main.syncバックグラウンドスレッドから呼び出すのは間違っているでしょうか?
Honey

@Honey一般的にいいえ、そのような呼び出しには何の問題もありません(メインキューが重くて時間のかかる処理を行わない限り)が、実際にはこれが本当に必要な状況は考えられません。間違いなくもっと良い解決策があるはずです
Andrey Chernukha '28 / 10/28

1
@Honeyそのような状況の1つは、PhotoKit APIからPHAssetsのCollectionViewを更新することです。ここのドキュメントに示されています:developer.apple.com/documentation/photokit/…–
teacup

1
@teacup面白い。私たちasyncがそこに電話した場合、それがどのように違うのか疑問に思っていますか?つまり、スレッドには他に何もないため、違いはありません。もしそうなら、それはDispatchQueue.main.sync {block1}; DispatchQueue.main.sync {block2};理にかなっていたでしょう。しかし、他にブロックがない場合、DispatchQueue.main.sync {Oneblock}over を使用するメリットを考えることができませんDispatchQueue.main.async {Oneblock}。どちらの場合も、mainQueueの優先度/即時性を取得し、何も中断しません。
ハニー

3
@Honeyは、「後でスレッドに他に何もないので」メインスレッドにいるときは当てはまりません。メインスレッドは、アプリとのすべてのユーザーインタラクションを処理する責任があります。したがって、たとえば、photoLibraryDidChangeが更新されたデータソースで戻り、致命的な不整合エラーが発生する前に、ユーザーが別の写真を削除する可能性があります。
2018年

160

なぜ並行性なのか?

データの読み込みなどの重いタスクをアプリに追加するとすぐに、UIの動作が遅くなったり、フリーズすることさえあります。並行性により、2つ以上のタスクを「同時に」実行できます。このアプローチの欠点は、スレッドの安全性が常に制御しやすいとは限らないことです。異なるスレッドで同じ変数を変更しようとしたり、異なるスレッドによってすでにブロックされているリソースにアクセスしたりするなど、異なるタスクが同じリソースにアクセスする場合。

認識しておく必要があるいくつかの抽象化があります。

  • キュー。
  • 同期/非同期タスクのパフォーマンス。
  • 優先事項。
  • 一般的なトラブル。

キュー

シリアルまたは同時でなければなりません。だけでなく、グローバルまたはプライベート同時に。

シリアルキューでは、タスクは1つずつ完了しますが、並行キューでは、タスクが同時に実行され、予期しないスケジュールで完了します。同じタスクのグループは、並行キューと比較して、シリアルキューの方が時間がかかります。

独自のプライベートキューシリアルまたは同時)を作成するか、すでに利用可能なグローバル(システム)キューを使用できますメインキューがあるだけで、シリアルキューのすべてのアウトのグローバルキュー

メインキュー(ネットワークからのデータのロード)でUI作業に言及されていない重いタスクを実行しないでください。代わりに、他のキューでそれらを実行して、UIのフリーズを維持し、ユーザーアクションに応答できるようにすることを強くお勧めします。他のキューでUIを変更すると、予期しない別のスケジュールと速度で変更が行われる可能性があります。一部のUI要素は、必要になる前または後に描画できます。UIがクラッシュする可能性があります。また、グローバルキューシステムキューであるため、システム上で実行できるタスクが他にもあることに注意してください。

サービス品質/優先度

また、キューにはさまざまなqos(サービス品質)があり、タスクの実行優先度(ここでは最高から最低を設定します。
.userInteractive - メインキューが
.userInitiatedを -ユーザー開始タスクのため、その上にいくつかの応答のためのユーザーの待機
.utility -タスク用これには時間がかかり、即時の応答は必要ありません。たとえば、データ
.backgroundの操作 -視覚部分に関連せず、完了時間が厳密ではないタスクの場合)。QoS情報を転送しない.defaultキュー

もあります。QoSを検出できなかった場合、

qos.userInitiated.utilityの間で使用されます。

タスクは同期または非同期で実行できます。

  • 同期関数は、タスクが終了した後にのみ、制御を現在のキューに戻します。キューをブロックし、タスクが完了するまで待機します。

  • 非同期関数は、別のキューで実行するタスクが送信された直後に、現在のキューに制御を戻します。タスクが完了するまで待機しません。キューをブロックしません。

一般的なトラブル。

同時実行アプリの投影中にプログラマが犯す最も一般的な間違いは次のとおりです。

  • 競合状態 -アプリの動作がコードパーツの実行順序に依存する場合に発生します。
  • 優先順位の逆転 -いくつかのリソースがブロックされているために、優先順位の高いタスクが優先順位の低いタスクが完了するのを待つ場合
  • デッドロック -ソース(変数、データなど)がこれらのキューのいくつかによってすでにブロックされているのをいくつかのキューが無限に待機している場合。

メインキューで同期関数を呼び出さないでください
メインキューで同期関数を呼び出すと、キューがブロックされ、キューはタスクの完了を待機しますが、キューが原因でタスクを開始できないため、タスクは完了しませんすでにブロックされています。これはデッドロックと呼ばれます。

同期を使用するタイミング タスクが完了するまで待つ必要がある場合。いくつかの関数/メソッドが二重に呼び出されないことを確認しているときのFe。同期が完了しており、完全に完了するまで二重に呼び出されないようにしています。この問題のコードを次に示します。
ます。IOSデバイスでエラークラッシュレポートが発生した原因を見つける方法は?


3
「メインキューの同期機能を絶対に呼び出さない」とは思わない。メインスレッドで同期を呼び出す場合があります。たとえば、グローバルカウンターがあり、各オブジェクトを使用して次の値を増やす必要がある場合です。dispatchQueue.sync {count + = 1; self.orderId = count}
Elisha Sterngold 2017年

6
QOSクラス-.userInteractiveはメインキューではありません。
Kunal Shah

1
DispatchQueue.main.syncバックグラウンドスレッドから呼び出すのは間違っているでしょうか?
Honey

1
@ハニー、それを呼び出すのは間違いありませんが、私の経験から、同期以外のDispatchQueue.main.asyncの多くを呼び出すことに気づくでしょう。
ジェームズ・キム

2
現在のキューでsync()関数を呼び出してはいけないと言った方が正確ではないでしょうか?私が正しく理解していれば、別のキューにいる場合、メインキューでsync()を呼び出すのは間違いありません。
ykay

0

syncまたはasyncメソッドは、それらが呼び出されるキューには影響しません。

syncスレッドブロックされますから、それはキューと呼ばされていない、それが呼び出されます。これは、がタスクの実行を待つDispatchQueueDispatchQueue(シリアルキュー)、現在のタスクが完了する前に次のタスクを実行できるか(同時キュー)を決定するプロパティです。

そのDispatchQueue.main.asyncため、非同期呼び出しの場合でも、メインスレッドでシリアルに実行される操作により、UIがフリーズする可能性があります。このメソッドがバックグラウンドスレッドから呼び出されると、UIがフリーズしているように見えても、制御は瞬時にそのスレッドに戻ります。これは、async呼び出しが行われるためですDispatchQueue.main


0

GCDタスクsynchronouslyまたはasynchronously[About] [More]を実行できます

synchronous(ブロックして待機)関数は、タスクが完了するとコントロールを返します

asynchronous(ディスパッチして続行)関数は、すぐにコントロールを返し、開始するタスクを適切なキューにディスパッチしますが、完了するまで待機しません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.