👽

DispatchQueueについて

2024/03/31に公開

DispatchQueueとは

DispatchQueueは、GCDフレームワークの一部であり並列処理を管理するAPIです。
役割としては、非同期にタスクを実行するためのキューを提供し、タスク実行の順番を管理しているクラスです。

タスクをスレッドに分けて並列や直列で実行します。
DispatchQueueの主なキューの種類にはMainとglobalがります。

DispatchQueue.Main

https://developer.apple.com/documentation/dispatch/dispatchqueue/1781006-main

DispatchQueue.Mainはメインスレッドでタスクを行うためのキューです。
メインスレッドにアクセスするときは、mainプロパティを使用します。

記述

DispatchQueue.main.async {}

挙動

DispatchQueueはデフォルトで直列の処理となっているので、追加された順に処理が実行され一つの処理が完了するまで次の処理を実行しません。
また、同じスレッド内に他のタスクがある場合はすべてのテスクの処理が完了するまで待ちます。

DispatchQueue.mainがデフォルトで直列なのは、メインスレッドはUIの変更を行う可能性があるので並列では矛盾が起きてしまうためです。

例)

DispatchQueue.main.async {
   print("1番目のタスク")
   print("2番目のタスク")
}
print("3番目のタスク")

DispatchQueueは直列ですべての処理が終わるまで待つので、main.asyncの中の処理は二つのプリント分が終わるまで出力されません。
つまり、下記のような順番になります。

出力)

3番目のタスク
1番目のタスク
2番目のタスク

DispatchQueue.global()

https://developer.apple.com/documentation/dispatch/dispatchqueue/2300077-global

DispatchQueue.global()は、デフォルトで並列処理を行いmainより自由度が高いシステム全体で共有される関数型のキューです。
メソッドであるため引数をもち、優先度を設定できます。また、asyncとsyncの両方を使うことができます。

DispatchQueue.global()は同期でも非同期でも実行できます。

記述

DispatchQueue.global.async {}
DispatchQueue.global.sync {}

挙動

ここで、同期と非同期についておさらいです。
DispatchQueue.global.sync(同期)は、タスクが順番に実行されます。あるタスクが始まるそのタスクの完了を待ってから次のタスクに移ります。
DispatchQueue.global.async(非同期)は、タスクの完了を待たずに他のタスクに移行します。

下記は非同期の処理です。
例)

DispatchQueue.gloabl().async {
   print("1番目のタスク")
   print("2番目のタスク")
}
print("3番目のタスク")

処理が早い順から実行されるので、上から順の出力で下記のようになります。

出力)

1番目のタスク
2番目のタスク
3番目のタスク

しかし、1番目のタスクが重ければ先に2番目の処理が実行されます。

出力)

2番目のタスク
1番目のタスク
3番目のタスク

予備知識

並列と非同期の違い。
Swiftに限らない話ですが、二つとも他のタスクの完了を待たずにタスクを次々と実行させます。
並列は複数のタスクを同時に実行することに焦点を当てた方式で、タスクを同時に実行して結果的に完了が早いタスクから処理が終わります。
一方で、非同期はタスクをバックグラウンドで実行し完了を待たずに次の処理に移ります。つまり、必ず同時に処理を行っているわけではありません。優先順位を下げて後で処理を行っている場合もあります。

gloabl()の引数

優先度

  • userInteractive
    • ユーザーからの入力をインタラクティブ(対話的)に反映させるために即座に実行させる必要がある場合に指定する優先度
  • userInitiated
    • ユーザーからの入力を受けてから反映させる場合に指定する優先度
  • default
  • utility
    • ユーザーが正確性を求めていないような処理を行う場合の優先度 プログレスバー中の処理など
  • background
    • バックグラウンドで行うような処理を行う場合の優先度

並列であるgloabl()を直列っぽくするには、groupで囲います。
groupで囲むと囲まれた処理がすべて終わるまでまち同時に完了します。

Discussion