6
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【GCD】DispatchQueueクラスの基本

Last updated at Posted at 2020-11-09

#DispatchQueueクラス
アプリのメインスレッドまたはバックグラウンドスレッドで、タスクの直列または並列な実行を管理するオブジェクト。

宣言
class DispatchQueue : DispatchObject

ディスパッチキューは、アプリケーションがブロックオブジェクトの形でタスクを渡せるFIFO(先入れ先出し)キューです。ディスパッチキューは、直列あるいは並列にタスクを実行します。ディスパッチキューに投入されたタスクは、システムによって管理されている「いずれかのスレッド」で実行されます。アプリのメインスレッドとなるディスパッチキューを除いて、システムは「どのスレッドでタスクを実行するか」を保証しません。

タスクは同期的または非同期的にスケジュールされます。同期的にタスクをスケジュールすると、コードはそのアイテムの実行が終了するまで次のタスクを待機します。非同期的に仕事アイテムをスケジュールすると、タスクが別の場所で実行されている間も、他のタスクは実行を続けます。

メインキューで仕事を同期的に実行しようとすると、デッドロックが発生します。

###余計なスレッドを作成しない
並列に実行するタスクを設計する際には、「実行中のスレッドをブロックするメソッド」を呼び出さないようにしてください。「並列ディスパッチキューによってスケジュールされたタスク」がそのスレッドをブロックすると、システムは「キューにある他の並列タスク」を実行するために追加のスレッドを作成します。あまりにも多くのタスクがブロックされると、システムはアプリのスレッドを使い果たす恐れがあります。

「プライベートな並列ディスパッチキュー」を作成することも、アプリのスレッドを消耗する原因になります。各ディスパッチキューはスレッドリソースを消費するので、追加の並行ディスパッチキューを作成すると、どんどんスレッドが消費されていきます。
プライベートな並列キューを作成する代わりに、「並列のグローバルディスパッチキュー」にタスクを投入します。直列なタスクの場合、シリアルキューのターゲットを「同時に実行できるグローバルキュー」のどれかに設定します。そうすることで、「個別のスレッドを作成するキュー」を最小限に抑えながら、 直列なキューの挙動を維持することができます。

##プロパティ
###mainプロパティ
現在のプロセスが持つメインスレッドに関連付けられたディスパッチキューです。

宣言
class var main: DispatchQueue { get }

システムは自動的に作成したメインキューをアプリケーションのメインスレッドに関連付けます。アプリは、以下にあげるアプローチのいずれか1つの方法で「メインキューに送信されたブロック」を実行します。

  • dispatchMain()メソッドを呼び出す
  • iOSではUIApplicationMain(_:_:_:_:)メソッド、macOSではNSApplicationMain(_:_:)メソッドを呼び出してアプリを起動する
  • メインスレッドのCFRunLoopを使用する

このプロパティ内のキューでsuspend()メソッド、resume()メソッド、 dispatch_set_context(_:_:)メソッドを呼び出しても、キューに影響はありません。

メインスレッドが応答しない時間が長すぎると、mach_msg_trapのメインスレッドで0x8badf00dの例外が発生する恐れがあります。iOSでは、アプリが特定のUIイベントへの応答に時間内に失敗したことを検出した場合、この例外が発生する恐れがあります。iOSにはUIの応答性を監視する番犬が存在します。

アプリにネットワーク接続のような実行に時間のかかるタスクがある場合は、システムのグローバルキューまたは別のバックグラウンドディスパッチキューで実行してください。可能であれば、非同期な呼び出しを使用します。

##メソッド
###global(qos:)メソッド
サービス品質レベルが指定された「システムのグローバルキュー」を返す。

宣言
class func global(qos: DispatchQoS.QoSClass = .default) -> DispatchQueue

このメソッドは、指定されたサービス品質レベルでタスクを実行するのに最適なキューを返します。suspend()resume()dispatch_set_context(_:_:)関数を呼び出しても、返されたキューに影響はありません。
返されたキューに投入されたタスクは、お互いを基準にして並列にスケジュールされます。

サービス品質レベルが標準のバックグラウンドキューを作成する例
let backgroundQueue = DispatchQueue.global(qos: .default)

##イニシャライザ

###init(label:qos:attributes:autoreleaseFrequency:target:)
「コードのブロック」を送信できるディスパッチキューを新たに作成します。

宣言
convenience init(label: String, 
                   qos: DispatchQoS = .unspecified, 
            attributes: DispatchQueue.Attributes = [], 
  autoreleaseFrequency: DispatchQueue.AutoreleaseFrequency = .inherit, 
                target: DispatchQueue? = nil)

以下、パラメータの説明です。

  • label
    クラッシュレポートなどのデバッグツールでキューを識別するためのラベル。アプリケーション、ライブラリ、フレームワークはすべて独自のディスパッチキューを作成することができるので、DNSの逆引きによる命名スタイル (com.example.myqueue) を推奨します。このパラメータはオプションで、NULLにすることもできます。

  • qos
    キューに関連付けるサービス品質レベル。システムがスケジュールするタスクの優先度は、この値によって決定されます。設定可能な値のリストについては、DispatchQoS.QoSClassを参照してください。

  • attributes
    キューに関連付ける属性です。concurrent属性を含めると、タスクを並列に実行するディスパッチキューを作成できます。この属性を省略した場合、 ディスパッチキューはタスクを直列に実行します。

  • autoreleaseFrequency
    キューが「スケジュールするブロックによって作成されたオブジェクト」を自動解放する頻度。設定可能な値の一覧は、DispatchQueue.AutoreleaseFrequencyを参照ください。

    • .inherit(ターゲットキューのオートリリース頻度を継承します)
    • .workItem(ブロックの実行が終了した後に解放します)
    • .never(実行後もブロックはオートリリースされません。)
  • target
    ブロックを実行するターゲットにするキュー。「現在のオブジェクトに適したキュー」をシステムに提供したい場合は、DISPATCH_TARGET_QUEUE_DEFAULTを指定します。

プライベートなバックグランドキューを作成する例
let videoDataOutputQueue = DispatchQueue(label: "VideoDataOutput", 
                                           qos: .userInitiated, 
                                    attributes: [], 
                          autoreleaseFrequency: .workItem)
6
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?