NSOperation vs Grand Central Dispatch


465

iOS用の並行プログラミングについて学んでいます。これまで、NSOperation/NSOperationQueueとについて読みましたGCDover を使用する理由とその逆の理由は何ですか?NSOperationQueueGCD

両方のような音GCDNSOperationQueue抽象化を明示的に作成するNSThreadsユーザから。ただし、2つのアプローチの関係は明確ではないため、フィードバックをお待ちしています。


10
良い質問の+1-結果に興味があります。これまでのところ、GCDをCPUコア全体に簡単にディスパッチして、「新しいホットなたわごと」にすることができると読んだところです。
までの


回答:


517

GCD低レベルのCベースのAPIで、タスクベースの同時実行モデルを非常に簡単に使用できます。NSOperationそして、NSOperationQueue同様のことを行うObjective-Cのクラスです。NSOperationが最初に導入されましたが、10.5およびiOS 2以降NSOperationQueue、友人はを使用して内部的に実装されていGCDます。

一般に、ニーズに合った最高レベルの抽象化を使用する必要があります。これは、サポートしていないことを行う必要がない限り、通常のNSOperationQueue代わりに使用する必要があることを意味します。GCDNSOperationQueue

これNSOperationQueueはGCDの「機能が低下した」バージョンではないことに注意してください。実際、NSOperationQueuepureで多くの作業を行うことで、非常に簡単にできることがたくさんありGCDます。(例:一度にN個の操作しか実行しない、帯域幅に制約のあるキュー。操作間の依存関係を確立します。どちらも非常に単純でNSOperation、非常に困難GCDです。)Appleは、GCDを利用して非常に優れたオブジェクトフレンドリーなAPIを作成するという大変な作業を行いましたNSOperation。あなたがそうしない理由がない限り、彼らの仕事を利用してください。

警告:一方、本当にブロックを送信する必要があるだけで、NSOperationQueue提供する追加機能が必要ない場合は、GCDの使用に問題はありません。それが仕事に適したツールであることを確認してください。


1
NSOperationは、特定の抽象クラスです。
Roshan 2014年

3
@Sandy実際には逆です。GCDはNSOperationで使用されます(少なくともiOSおよびOS Xの以降のバージョン)。
garrettmoon 2014

1
@BJ Homer依存性を達成するために、タスクをシリアルディスパッチキューに追加できます。操作キューがそれよりも優れていることを
正当化

3
@RajAggrawalはい、それはうまくいきます…しかし、それからあなたはシリアルキューで立ち往生しています。NSOperationは、「他の3つが完了した後で、他のすべての処理と同時に、この操作を実行する」ことができます。操作の依存関係は、異なるキューの操作間にも存在する可能性があります。ほとんどの人はそれを必要としないでしょうが、もしそうなら、NSOperationがより良い選択でしょう。
BJホーマー

369

関連する質問への私の回答に沿って、私はBJに同意せず、最初にNSOperation / NSOperationQueueを介してGCDを確認することをお勧めします。

GCD以前は、同時実行性を管理するために、アプリケーション内で多くのNSOperations / NSOperationQueuesを使用していました。ただし、定期的にGCDを使い始めて以来、NSOperationsとNSOperationQueuesをほぼ完全にブロックとディスパッチキューに置き換えました。これは、実際に両方のテクノロジーをどのように使用したか、およびそれらに対して実行したプロファイリングに基づいています。

まず、NSOperationsとNSOperationQueuesを使用すると、かなりのオーバーヘッドが発生します。これらはCocoaオブジェクトであり、割り当てと割り当て解除を行う必要があります。60 FPSで3Dシーンをレンダリングする私が書いたiOSアプリケーションでは、NSOperationsを使用して、レンダリングされた各フレームをカプセル化していました。私がこれをプロファイリングしたとき、これらのNSOperationsの作成と破棄は、実行中のアプリケーションのCPUサイクルのかなりの部分を占めていて、物事を遅くしていました。これらを単純なブロックとGCDシリアルキューに置き換えたところ、そのオーバーヘッドがなくなり、レンダリングパフォーマンスが著しく向上しました。私がNSOperationsの使用によるオーバーヘッドに気づいたのはここだけではなく、MacとiOSの両方でこれを確認しました。

第2に、NSOperationsを使用するときに一致させるのが難しいブロックベースのディスパッチコードには優雅さがあります。数行のコードをブロックにラップし、それをシリアルキューまたは並行キューで実行するようにディスパッチするのは非常に便利です。これを行うには、カスタムNSOperationまたはNSInvocationOperationを作成するために、より多くのサポートコードが必要です。NSBlockOperationを使用できることは知っていますが、その場合はGCDに何かをディスパッチすることもできます。このコードをアプリケーションの関連処理とインラインでブロックでラップすると、これらのタスクをカプセル化する個別のメソッドやカスタムNSOperationsを使用するよりも、コードの編成が良くなります。

NSOperationsとNSOperationQueuesは、依然として非常に優れた用途があります。GCDには依存関係の実際の概念はありません。NSOperationQueuesはかなり複雑な依存関係グラフを設定できます。NSOperationQueuesを使用するのは、ほんの一握りの場合です。

全体として、私は通常、タスクを実行する最高レベルの抽象化を使用することを推奨していますが、これは、GCDの低レベルのAPIを主張する1つのケースです。私がこれについて話し合ったiOSとMacの開発者の中で、大多数がサポートしていないOSバージョン(iOS 4.0とSnow Leopardより前のもの)をターゲットにしていない限り、NSOperationsよりもGCDを使用することを選択します。


20
私は少しだけ反対します。プレーンGCDをかなり使用しています。しかし、私はあなたがこの回答でNSBlockOperationを大幅に割り引いていると思います。NSOperationQueueのすべての利点(依存関係、デバッグ可能性など)は、ブロック操作にも適用されます。
BJホーマー

4
@BJHomer-私の場合、NSBlockOperationの回避は個人的な好みの問題であると思いますが、NSOperationsの使用によるオーバーヘッドがいくつかのアプリケーションをドラッグダウンするのを見て、一般的にNSOperationsを回避しました。ブロックを使用する場合は、依存関係のサポートが必要な場合を除いて、GCDをオールインする傾向があります。
ブラッド・ラーソン

1
+1、この分析に感謝します。Appleは両方(WWDC 2012の同時UIのセッションなど)を推奨しているようで、これは非常にありがたいことです。
orip

1
@VolureDarkAngel-GCDは、そのようなディスパッチの処理が非常に高速です。I / Oアクセスが遅いなどの理由で更新の山をキューに何らかの方法でバックアップしない限り、このような状況ではボトルネックにならないはずです。しかし、おそらくここではそうではありません。
ブラッド・ラーソン

1
@ asma22-チャンクで計算できる計算が一般的ですが、1つのステージの最終計算では、以前のいくつかのステージの結果が必要になる場合があります。その場合、後の操作を前の操作に依存させることができ、最後の操作が実行される前にすべてが完了するようにスケジューリングが管理されます。
ブラッド・ラーソン

101

GCD低レベルのCベースのAPIです。
NSOperationそして、NSOperationQueueObjective-Cのクラスです。
NSOperationQueue目的のCラッパーGCDです。NSOperationを使用している場合は、暗黙的にGrand Central Dispatchを使用しています

NSOperationに対するGCDの利点:
i。実装
GCD実装が非常に軽量
NSOperationQueueで複雑で重い

GCDに対するNSOperationの利点:

私。Control On Operation
では、一時停止、キャンセル、再開できます。NSOperation

ii。
2つのNSOperations
操作間の依存関係を設定できる依存関係は、その依存関係がすべてtrueに戻るまで開始されません。

iii。操作
の状態は、操作または操作キューの状態を監視できます。準備完了、実行中または終了

iv。最大
操作数:同時に実行できるキューに入れられた操作の最大数を指定できます

いつ、GCDまたはNSOperation
キュー(上記のすべて)をより詳細に制御する必要があるNSOperation およびオーバーヘッドを減らしたい単純な場合(追加の作業をほとんど行わずに「バックグラウンドで」いくつかの作業を実行したいだけ)GCD

ref:
https : //cocoacasts.com/choosing-between-nsoperation-and-grand-central-dispatch/ http://iosinfopot.blogspot.in/2015/08/nsthread-vs-gcd-vs-nsoperationqueue.html http ://nshipster.com/nsoperation/


前述のように、オペレーションの最大数はNSOperationQueueで指定できます。次に、GCDのオペレーション(ディスパッチキュー)の最大数はいくつになりますか?プロジェクトがあるとしたら、いくつの操作(ディスパッチキュー)を実行できますか。または、私たちができる最大の限界です。
Roshan Sah 2018年

これは、システム条件は、ここで詳述されている情報に依存します。stackoverflow.com/questions/14995801/...
Sangram Shivankar

DispatchWorkItemを使用してGCDでタスクをキャンセルすることもできます。また、中断して再開することもできます
Ankit garg

@Ankitgarg DispatchWorkItemでキャンセルを呼び出すと、タスクがまだ実行されていない場合は実行が停止されますが、すでに実行中のタスクは停止されません。そして、どのようにDispatchWorkItemを一時停止/再開しますか?
abhimuralidharan

34

GCDよりもNSOperationを選ぶもう1つの理由は、NSOperationのキャンセルメカニズムです。たとえば、数十枚の写真を表示する500pxのようなアプリでは、NSOperationを使用して、テーブルビューまたはコレクションビューをスクロールするときに非表示の画像セルのリクエストをキャンセルできます。これにより、アプリのパフォーマンスが大幅に向上し、メモリフットプリントを削減できます。GCDはこれを簡単にサポートできません。

また、NSOperationを使用すると、KVOが可能になります。

ここで読書の価値があるEschatonからの記事です。


4
それはあなたがキャンセルされていることは、画像を読み込むのネットワーク操作がある場合、その後、あなたが必要としないことは注目に値するNSOperationとして、このために NSURLSessionTask.cancelNSURLSession.invalidateAndCancel、この機能を提供します。一般的に、NSURLSessionの機能の一部を提供するNSOperationQueueよう、NSURLSessionTaskの機能の一部を提供NSOperation
藻類

@algalここで説明しているように(stackoverflow.com/questions/21918722/…)、NSURLSessionはNSOperationQueueをビルディングブロックとして使用しているようです。
kalan nawarathne

33

GCDは確かにNSOperationQueueよりもレベルが低く、その主な利点は、その実装が非常に軽量で、ロックのないアルゴリズムとパフォーマンスに重点を置いていることです。

NSOperationQueueはGCDで利用できない機能を提供しますが、それらは重要なコストで提供されます。NSOperationQueueの実装は複雑で重量があり、多くのロックを含み、GCDを内部で使用するのは最小限の方法のみです。

NSOperationQueueが提供する機能が必ず必要な場合は、それを使用してください。ただし、GCDで十分な場合は、直接使用して、パフォーマンスを向上させ、CPUと電力のコストを大幅に削減し、柔軟性を高めることをお勧めします。


24

NSQueueOperationsとGCDはどちらも、UIアプリケーションのメイントレッドを解放することで、バックグラウンドで個別のスレッドで重い計算タスクを実行できます。

さて、以前の投稿に基づいて、NSOperationsにはaddDependencyがあるため、次々に操作をキューに入れることができます。

しかし、作成できるGCDシリアルキューについても読んで、dispatch_queue_createを使用してキューで操作を実行します。これにより、一連の操作を順番に実行できます。

GCDに対するNSQueueOperationの利点:

  1. 依存関係を追加したり、依存関係を削除したりできるため、1つのトランザクションでは依存関係を使用して順次実行でき、他のトランザクションでは同時に実行できますが、GCDではこの方法で実行できません。

  2. 操作がキューにある場合、操作をキャンセルするのは簡単です。実行中の場合は停止できます。

  3. 同時操作の最大数を定義できます。

  4. キューにある操作を一時停止できます

  5. キューにある保留中の操作の数を確認できます。


6

GCDは非常に使いやすく、バックグラウンドで何かを実行したい場合は、コードを記述してバックグラウンドキューにディスパッチするだけです。NSOperationで同じことを行うには、追加の作業がたくさんあります。

NSOperationの利点は、(a)メッセージを送信できる実際のオブジェクトがあり、(b)NSOperationをキャンセルできることです。それは簡単なことではありません。NSOperationをサブクラス化する必要があります。キャンセルとタスクの正常終了の両方が正しく機能するように、コードを正しく記述する必要があります。したがって、単純なものにはGCDを使用し、より複雑なものにはNSOperationのサブクラスを作成します。(サブクラスNSInvocationOperationとNSBlockOperationがありますが、それらが行うすべてのことはGCDで簡単に行えるため、それらを使用する十分な理由はありません)。


3

まあ、NSOperationsは単にGrand Central Dispatchの上に構築されたAPIです。したがって、NSOperationsを使用しているときも、Grand Central Dispatchを実際に使用しています。NSOperationsがあなたが好きかもしれない素晴らしい機能を提供するだけです。一部の操作を他の操作に依存させたり、アイテムを合計した後にキューを並べ替えたりすることができます。実際、ImageGrabberはすでにNSOperationsと操作キューを使用しています!ASIHTTPRequestは内部でそれらを使用します。必要に応じて、さまざまな動作に使用する操作キューを設定できます。それであなたはどちらを使うべきですか?アプリにとって意味のある方。このアプリは非常にシンプルなので、Grand Central Dispatchを直接使用しただけで、NSOperationの豪華な機能は必要ありません。ただし、アプリでそれらが必要な場合は、自由に使用してください。

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