https://www.raywenderlich.com/5370-grand-central-dispatch-tutorial-for-swift-4-part-1-2

これはswiftシリーズの並行性の続きです。 基本を理解するには、パート1とパート2を参照してください

このパートでは、次のトピックをカバーします

  1. 操作とは何か、それはライフステート
  2. ブロック、NSInvocationOperation、およ操作キューに操作を追加する方法
  3. 操作間の依存関係を作成する方法
  4. gcdに対する操作キューの利点
  5. 操作キューを使用したディスパッチグループ実装

操作は 非同期に実行する作業をカプセル化するオブジェクト指向の方法。 操作は、操作キューと一緒に使用するか、それ自体で使用するように設計されています

操作オブジェクトは、アプリケーションで実行する作業をカプセル

Operationクラス自体は抽象基底クラスであり、有用な作業を行うためにサブクラス化する必要があります。 抽象的であるにもかかわらず、このクラスは、独自のサブクラスで行う必要がある作業の量を最小限に抑えるためのかなりの量のインフラストラクチャを提供します。 さらに、Foundationフレームワークには、既存のコードでそのまま使用できる2つの具体的なサブクラスが用意されています。

操作状態

操作には、そのライフサイクルを表すステートマシンがあります。 このライフサイクルのさまざまな部分で発生する可能性のある状態がいくつかあります:

  • それがinstantiatedされているとき、それはisReady状態に移行します。
  • startメソッドを呼び出すと、isExecuting状態に遷移します。
  • タスクfinishedが進行中でcancelを呼び出すと、isCancelled状態に遷移し、isFinished状態

操作を作成するには、主に三つの方法があります

BlockOperation(具体的なクラス)

1つまたは複数のブロックオブジェクトを同時に実行するためにそのまま使用するクラス。 複数のブロックを実行できるため、ブロック操作オブジェクトはグループセマンティックを使用して動作します; 関連するすべてのブロックの実行が終了した場合にのみ、操作自体が終了したと見なされます。. ブロック操作では、操作の依存関係、KVO、通知、キャンセルを利用することができます。

図1に示すように、このコードasyncを実行しました。つまり、すぐに戻りますが、悪いニュースは、operation.start() がメインスレッド

オペレーションオブジェクトがデフォルトで同期的に実行されるため、メインスレッドをブロックすることです。つまり、startメソッドを呼び出すスレッドでタスクを実行します。

フィギュア1

一体何が同期的な方法であり、同時に1つ以上のブロックオブジェクトを実行します。

図1.0.1に示すように、ブロック操作自体に追加されたタスク/ブロックは同時に実行されますが、ブロックは同期的に実行されます。

図1.0.1

図1.0.2に示すように、他のスレッドでstartメソッドを呼び出すので、そのスレッドをブロックします

フィギュア1.0.2

図1.0.3に示すように、すべての同時ブロックが実行されるときに呼び出すcompletionブロックを追加することもできます

フィギュア1.0.3

図1に示すように、ブロック操作を同時に実行します

。1バックグラウンドスレッドでstart()メソッドを呼び出すので、スレッド内でタスクを実行します。 Operation queueを使用してこれを行うためのクールな方法があり、これは後で見ていきます。

フィギュア1.1

NSInvocationOperation(具体的なクラス)

アプリケーションのオブジェクトとセレクタに基づいてoperationオブジェクトを作成するためにそのまま使用するクラス。Objective Cでは、Swiftでは利用できませんが、NSInvocationOperationを作成できます。

https://developer.apple.com/library/archive/documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationObjects/OperationObjects.html#//apple_ref/doc/uid/TP40008091-CH101-SW6

3. カスタム操作

サブクラス化Operation を使用すると、操作が実行され、その状態を報告するデフォルトの方法を変更する機能を含む、独自の操作の実装を完

図2に示すように、Operation基本クラスからサブクラス化し、そのmainメソッドをオーバーライドするカスタム操作を作成しました。 サブクラス化すると、タスクをmainメソッドに配置します。 非同時カスタム操作を実装し、この場合はメインスレッドをブロックしました

フィギュア2

操作を手動で実行しても非同期で実行する場合は、適切なアクションを実行して確実に実行する必要があります。 これを行うには、operationオブジェクトを並行操作として定義します。

図3に示すように、タスクを同時に実行するために次の手順を実行しました

  1. 作成されたサブクラスMyConcurrentQueue。 誤字: 名前はMyConcurrentOperations
  2. start()メソッドを呼び出すと、バックグラウンドスレッドでmain()メソッドが呼び出されます
  3. メインメソッドでタスクを定義し、カスタム操作で
  4. を呼び出すと、cancelカスタム操作でisCancelled状態に遷移し、ループを解除し、図3に示すように、39487アイテムのみが出力されます。

フィギュア3

操作キュー

  1. 操作キューは、Gcd
  2. 上のCocoaの高レベル抽象化です。 操作キューあなたは代わりに、操作を自分で開始するのではなく、操作の本当の力が表示されます、あなたはそれがその後、スケジューリングと実行を処
  3. 操作キューは、非同期に実行する作業をカプセル化するオブジェクト指向の方法です。
  4. operation queueoperations(tasks/work)を追加し、二つの方法を使用して操作を作成する方法について議論しました。

操作の追加

図4に示すように、2つの操作(ブロックを使用)を作成し、それらを操作キューに追加しました。 操作キューは、いくつかのバックグラウンドスレッド上の両方の操作を開始し、それらを実行しました。 カスタムスレッド🆒でstart()メソッドを呼び出す必要はありません。 操作キューに操作を追加すると、準備が整うとすぐに実行されます

フィギュア4

図5に示すように、タスクを直列に実行しただけであるか、Operation Queuesを使用してシリアルキューを実装したと言うことができます。maxConcurrentOperationCount = 1

maxConcurrentOperationCount →同時に実行できるキューに入れられた操作の最大数。 デフォルト値は-1であり、システムが決定することを意味します

フィギュア5

maxConcurrentOperationCount=2を設定することで、同時キューを作成し、図に示すようにタスクが同時に実行されるようになりました6

フィギュア6

Operations Dependencies

図7に示すように、2つのタスク間に依存関係を追加して、シリアルキューを再度作成しました。 私たちは2つのブロック操作を作成し、タスク2が終了するまでタスク1を開始しないと言っていますblockOperations1.addDependency(blockOperations2)

フィギュア7

Operations Queue

を使用したディスパッチグループの実装パート2では、GCDディスパッチグループ機能を使用して、一つ以上のタスクの実行が完了するまでスレッドをブ 図8に示すように、依存関係を使用して操作キューを使用して同じ動作を実装しました。 これは、指定されたすべてのタスクが完了するまで進行できない場合に非常に役立ちます。

図8に示すように、三つのタスクがあり、同時に実行したいと思っていました。

  1. 操作キューを作成しました
  2. タスクを実行する三つのブロック操作を作成しました
  3. 三つのタスクがすべて終了したときにトリガする完了ブロック操作(blockoperations4)を作成しました
  4. blockOperations4blockOperations1blockOperations2blockOperations3に依存させました。
  5. waitUntilFinished → メインである現在のスレッドをブロックしたくないので、operationオブジェクトがタスクを終了するまで現在のスレッドの実行をブロックします。false
  6. このコードを実行すると、task1、task2、task3が終了すると”すべての操作が完了しました”と出力されます。

フィギュア8

図9に示すように、waitUntilFinished = true. を設定してメインスレッドをブロックするだけなので、問題はいつ役立つかであり、次のセクションで答えを得ることになりま

フィギュア9

図10に示すように、依存関係を使用せずにoperation queueを使用してディスパッチグループの動作を実装しましたwaitUntilFinished 機能を適切に使用しました。 バックグラウンドスレッドを使用している場合は、このスレッドをブロックしてこの動作を実現できます。 私は意図的にDispatchQueue.global().asyncメソッドを使用してバックグラウンドスレッドに切り替えましたこのコードを理解するためにパート1を参照してください

私たちはoperation queue run task1,task2and task3on operation queueと、これらの同時タスクが実行を終了するまで現在のスレッドをブロックします

フィギュア10

Gcd

  1. を超える操作キューの利点操作APIは依存関係をサポートします。 タスク間の複雑な依存関係を非常に簡単に作成できますが、GCDではそれを達成できますが、多くの作業を行う必要があります。
  2. NSOperationクラスとNSOperationQueueクラスには、KVO(Key Value Observing)を使用して観測できる多くのプロパティがあります。 これは、操作または操作キューの状態を監視する場合に、もう一つの重要な利点です。
  3. 操作は一時停止、再開、キャンセルすることができます。 Grand Central Dispatchを使用してタスクをディスパッチすると、そのタスクの実行に関する制御や洞察がなくなります。 NSOperation APIはその点でより柔軟であり、開発者が操作のライフサイクルを制御できるようにします
  4. NSOperationQueueはまた、ミックスに多くの利点を追加します。 たとえば、同時に実行できるキューに入れられた操作の最大数を指定できます。 これにより、同時に実行される操作の数を制御したり、シリアル操作キューを作成したりすることが容易になります。

今後の

次の部分では、カスタム操作を作成する実際のユースケースを見ていきます

便利なリンク

· https://developer.apple.com/library/archive/documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationObjects/OperationObjects.html#//apple_ref/doc/uid/TP40008091-CH101-SW1

コメントを残す

メールアドレスが公開されることはありません。