web-dev-qa-db-ja.com

別のスレッドでメソッドを呼び出すためのさまざまな方法は何ですか?

いくつかのデータ計算メソッド(「myMethod:」とします)があり、メインのUI機能をブロックしたくないので、呼び出しを別のスレッドに移動したいと思います。そこで、別のスレッドでメソッドを呼び出す方法について調査を開始しました。私が見る限り、現在、それを行うには多くの異なる方法があります。リストは次のとおりです。

a)純粋なスレッドの使用(iOS 2.0以降で利用可能):

[NSThread detachNewThreadSelector:@selector(myMethod:) toTarget:self withObject:_myParamsArray];

b)単純なショートカットを使用する(iOS 2.0以降で使用可能)。継承されたNSObjectから利用できますが、メソッドもNSThreadクラスに属しています。

[self performSelectorInBackground:@selector(myMethod:) withObject:_myParamsArray];

c)Grand Central Dispatchキューの新しいアプローチを使用する(iOS 4.0以降で使用可能):

dispatch_async(dispatch_get_global_queue(0, 0),
  ^ {
      [self myMethod:_myParamsArray];
    });

d)どういうわけか、NSOperation、NSBlockOperation、NSOperationQueueなどのいくつかのクラスを使用しますが、正確にそれを行う方法はわかりません(いくつかの例をいただければ幸いです)

現在、私はケース「b」を使用していますが、賛否両論やその他の関連する提案に興味があります。

更新:e)同様のスレッド処理を実行する別の方法も見つかりました ループの実行 。 Appleドキュメントからの抜粋です:

実行ループは、作業をスケジュールし、着信イベントの受信を調整するために使用するイベント処理ループです。実行ループの目的は、実行する作業がある場合はスレッドをビジー状態に保ち、作業がない場合はスレッドをスリープ状態にすることです。

私見、多かれ少なかれあなたは同じタスクを扱っています-非同期操作のために別のスレッドでメソッドを呼び出す方法。

UPDATE2:NSInvocationOperationとNSOperationQueueおよびIMHOの経験はすでにあり、非常に便利です。 Apple docsによると、マルチスレッドを実装するにはGCDとNSOperationsが推奨されます。また、NSOperationsはiOS 4.0以降のGCDで実行されます。つまり、NSIvocationOperationを(メソッドの呼び出しとして)インスタンス化します。 )次に、NSOperationQueueをインスタンス化し、キューに呼び出しを追加します。NSOperationQueueは十分に賢いので、複数のNSIvocationOperationオブジェクト(メソッド呼び出しをラップ)をインスタンス化して、それらをNSOperationQueueにインスタンス化できます。残りは保証されます。NSOperationQueueは、 (NSInvocationOperation)を呼び出して処理します。最初の呼び出しはスレッドAで実行され、次にスレッドBで実行され、次にスレッドCで実行され、3番目がスレッドBで実行される可能性があるため、心配する必要はありません。 NSOperationQueueが呼び出しの実行に使用できる最大スレッド数(たとえば1)はわかりますが、その必要はありません。デフォルトでは、すべてのタスクはメインスレッド以外で実行されるため、操作キューは非同期です。デフォルトでは。また、厳密なキューでメソッド呼び出し(それぞれが個別のNSInvocationOperationにラップされている)を実行する場合は、依存関係を追加できるため、NSOperationQueueはメソッド呼び出しの順序を保持します。次に例を示します。

// wrap your method call into NSInvocationOperation object
NSInvocationOperation *currentOperation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(yourMethodCall) object:nil];

// _sharedOperationQueue is a shared NSOperationQueue 
// get all executing operations from the queue and get the last operation
_lastOperation = [[_sharedOperationQueue operations] lastObject];

// check if _lastOperation is not nil
if (_lastOperation) {

    // if not then add dependency, so the calls would be performed in a queue
    [currentOperation addDependency:_lastOperation];
}

// say - execute my method (operation)
[_sharedOperationQueue addOperation:currentOperation];

_lastOperation = currentOperation; // mark as last operation for adding dependency to the next operation

// the queue will retain invocation operation so you will release
[currentOperation release];

 ..... you can create another NSInvocationOperation and add it to the queue....

RUNLOOPに関しては、それでも、タイマーの開始/スケジュール設定やNSURL接続の作成などで直面することがあります。 IMHO、runloopは、1つのスレッドで実行されるタスクのキューと比較される場合があります。 IMHO runloopは、キューとして動作するスレッドへのポインターです。イベントをスローする可能性のあるタスクがあり、それらはそのスレッドのキューの最後に配置されます。デフォルトでは、アプリ内のすべてのタスクは単一の実行ループで、つまり単一のスレッドで実行されます。アプリがイベントを生成するとき、アプリはそのイベント(タッチイベントまたは他のデリゲートコールバック)を実行する場所を知っている必要があるため、これはポインターだと言っています。もちろん、これらは私の考えにすぎないので、より詳細な情報についてはrunloopsについて読む必要があります。

31
Centurion

通常、GCDアプローチをお勧めします。

同期/ロックに関しては、純粋なスレッド(NSThread-pthread)よりも単純であり、パフォーマンスの観点からはより正確である可能性があります。

純粋なスレッドを使用する場合、問題は、使用可能なコア/プロセッサの数によっては、パフォーマンスの問題が発生する可能性があることです。

たとえば、コアが1つしかない場合、CPUがスレッド間の切り替え、スタック、レジスタなどの保存にほとんどの時間を費やすため、多くのスレッドを作成するとアプリケーションの速度が低下する可能性があります。

一方、利用可能なコアがたくさんある場合は、さまざまなスレッドを作成するとよいでしょう。

これは、GCDがこれを管理するために役立つ場所です。利用可能なシステムリソースに基づいて適切な数のスレッドを作成し、最適な使用率を保証し、アクションを適切にスケジュールします。

ただし、そのため、GCDで起動されたタスクはリアルタイムではない場合があります。

したがって、デタッチされたタスクをすぐに実行する必要がある場合は、明示的なスレッドを使用してください。それ以外の場合は、GCDを使用してください。

これがお役に立てば幸いです:)

[〜#〜]編集[〜#〜]

performSelectorInBackgroundに関する注意:新しいスレッドを作成するだけです。したがって、基本的にNSThreadアプローチとの違いはありません。

編集2

NSOperation関連のものは少し異なります。 Mac OS Xでは、バージョン10.6以降のGCDを使用して実装されています。以前のバージョンはスレッドを使用します。

IOSでは、スレッドのみを使用して実装されます。

参照

これらすべては、 並行性プログラミングガイド で非常によく説明されています。 GCDとスレッドのアプローチについて説明し、使用法と実装について多くの詳細を示します。

まだ読んでいない場合は、ご覧ください。

25
Macmade

これは、この古い質問に対する更新された回答です。 NSOperationsは、macosとiosの両方のlibdispatchで実装されるようになりました。彼らはしばらくの間ありました。別のスレッドを呼び出すための推奨される方法は、libdispatchまたはNSOperationsのいずれかを使用することです。覚えておくべき主なアイデアは、「サービス品質」または「QOS」です。 QOSはスレッドに割り当てられたものであり、ディスパッチキュー、NSOperationQueue、またはNSOperationに割り当てると、基本的に「このQOSが割り当てられたスレッドでこれを実行したい」と言います。特別な場合はメインスレッドです。

NSThreadを使用する場合もあるかもしれませんが、私は長い間使用していません。

0
drkibitz