👏

【翻訳】Parallel Programming with Swift — Part 3/4

2023/07/22に公開

この記事は、Swiftによる並列プログラミングシリーズのパート3です。パート1では、 Dispatch Queue とシステムが提供するキューについて調べました。パート2では、タスクを定義する別の方法と、 GCD によって提供される強力な API に焦点を当てました。今回は、 Grand Central Dispatch と比較して、 Operation API とその柔軟性について見ていきましょう。

このシリーズの全てのパートをご覧になりたい方は、こちらをクリックしてください。

Concurrency & GCD — Parallel Programming with Swift — Part 1/4 (https://medium.com/swift-india/parallel-programming-with-swift-part-1-4-df7caac564ae)

GCD — Parallel Programming with Swift — Part 2/4 (https://medium.com/swift-india/parallel-programming-with-swift-part-2-4-46a3c6262359)

Operation

Operation は、非同期に実行する必要がある作業をカプセル化するオブジェクト指向の方法です。

Operation は1つの作業単位を表します。 Operation は抽象クラスで、状態、優先度、依存関係、管理をモデル化するのに便利な、スレッドセーフな構造を提供します。

  • NSHipster

Operation は抽象クラスなので、直接使うことはできません。 Foundation には、タスクを実行するためのシステム定義のサブクラス InvocationOperation と BlockOperation が用意されています。定義されたサブクラスを使えば、タスクの実際の実装に集中することができます。

オペレーションは一度だけタスクを実行します。オペレーションを実行するには、オペレーション・キューに追加します。オペレーション・キューは、セカンダリー・スレッド上で直接オペレーションを実行するか、libdispatch ライブラリ(Grand Central Dispatchなど) を使って間接的にオペレーションを実行します。このように、オペレーション API は Grand Central Dispatch をより高度に抽象化したものです。

不思議に思うかもしれない:タスクって何?と。

これらの用語について説明しましょう。

・ タスク

やらなければならない1つの仕事。

・ プロセス

複数のスレッドで構成される実行可能なコードの塊。プロセスはアプリのインスタンスです。アプリのコールドローンチを行うと、プロセスIDが変更されます。プロセスには、スタック、ヒープ、その他すべてのリソースなど、アプリの実行に必要なものが全て含まれています。

・ スレッド

オペレーティングシステムが提供する仕組みで、1つのアプリケーション内で複数の命令セットを同時に実行できるようにするもの。プロセスと比べて、スレッドは親プロセスとメモリを共有します。このため、2つのスレッドが同時にリソース(変数など)を変更するなどの問題が発生する可能性があります。iOSではスレッドは限られたリソースです。1つのプロセスで同時に64スレッドまでと制限されていますが、コンテキストやコア数によって異なるため、どのドキュメントにも公式には記載されていません。

for element in 0..<30000 {
    DispatchQueue.global().async {
    print(element)
    Thread.sleep(forTimeInterval: 10000)
   }
}

Operation は start() メソッド を呼び出すことで直接実行できます。しかし、これにはそれなりのオーバーヘッドが伴います。手動でオペレーションを実行すると、コードに負担がかかります。なぜなら、準備状態でないオペレーションを開始すると例外が発生するからです。 isReady プロパティ は、 Operation の準備状態を報告します。

Operation はクラスなので、それを使ってビジネスロジックをカプセル化することができます。

Operation を使用できるタスクの例としては、ネットワーク要求、画像のリサイズ、テキスト処理、バックグラウンド・フェッチでのプリフェッチの実行、または関連する状態やデータを生成するその他の長時間実行タスクがあります。アプリケーションのログインシーケンスの実装にも使用できます。 Operation は他の Operation と依存関係を持つことができ、これは Grand Central Dispatch に欠けている強力な機能です。複数のタスクを特定の順序で実行する必要がある場合、 Operation は良い解決策になります。

オペレーション・ライフサイクル:

オペレーション・ステート

オペレーション・オブジェクトは、いつ実行すれば安全かを判断するために内部でステートを維持し、またオペレーションのライフサイクルの進捗状況を外部クライアントに通知します。

isReady

オペレーションが実行可能な状態になったことをクライアントに通知します。このキーパスは、オペレーションが今すぐ実行可能な場合は true を返し、依存する未完了のオペレーションが残っている場合は false を返します。

isExecuting

このキーパスは、操作が割り当てられたタスクでアクティブに動作しているかどうかを知らせます。 isExecuting は、操作がそのタスクで動作している場合は true を返し、動作していない場合は false を返します。

isFinished

これは、オペレーションがそのタスクを正常に終了したか、キャンセルされたかを知らせます。オペレーション・オブジェクトは、 isFinished キー・パスの値が true に変わるまで、依存関係をクリアしません。同様に、操作キューは、isFinished プロパティに値 true が含まれるまで、操作をデキューしません。

isCancelled

isCancelled キー・パスは、操作のキャンセルが要求されたことをクライアントに通知します。

start()メソッドが呼び出される前に操作をキャンセルすると、タスクを開始せずに start()メソッドが終了します。

OperationQueue

オペレーション・キューは、キューに入れられたOperationオブジェクトを、優先順位とレディネスに基づいてFIFOオーダーで実行します。オペレーション・キューに追加されたオペレーションは、そのタスクが終了するまでキューに残ります。オペレーションは、追加された後、キューから直接削除することはできません。

オペレーション・キューは、オペレーションが終了するまで保持され、キュー自体も、全てのオペレーションが終了するまで保持されます。終了していないオペレーションでオペレーションキューを一時停止すると、メモリ・リークを引き起こす可能性があります。

キュー内のオペレーションは、準備状況(isReadyプロパティがtrueを返す)、優先度、依存関係に従って整理され、それに従って実行されます。キューに入れられた全てのオペレーションが同じ queuePriority を持ち、キューに入れられた時点で実行準備が整っている場合、それらはキューに投入された順に実行されます。そうでない場合、オペレーションキューは常に、他の実行可能なオペレーションに対して最も高い優先度を持つものを実行します。

オペレーション・オブジェクトは、それに従属する全てのオペレーションの実行が終了するまで、実行準備が整ったとは見なされません。

【翻訳元の記事】

Parallel Programming with Swift — Part 3/4
https://medium.com/swift-india/parallel-programming-with-swift-part-3-4-28a57584221c

Discussion