7

私は、NSURL ロードと Web からのイメージを提供し、完了ブロックを実行するイメージ ローダー クラスを持っています。コードは実際には非常に単純です

- (void)downloadImageWithURL:(NSString *)URLString completion:(BELoadImageCompletionBlock)completion
{
    dispatch_async(_queue, ^{
//    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
        UIImage *image = nil;
        NSURL *URL = [NSURL URLWithString:URLString];
        if (URL) {
            image = [UIImage imageWithData:[NSData dataWithContentsOfURL:URL]];
        }  
        dispatch_async(dispatch_get_main_queue(), ^{
            completion(image, URLString);
        });
    });

}

交換したら

dispatch_async(_queue, ^{

コメントアウトして

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{

画像の読み込みがはるかに高速になりました。これは非常に論理的です (以前は画像が一度に 1 つずつ読み込まれていましたが、現在は多数の画像が同時に読み込まれています)。私の問題は、おそらく 50 個の画像があり、それらすべてに対して downloadImageWithURL:completion: メソッドを呼び出し、_queue の代わりにグローバル キューを使用すると、アプリが最終的にクラッシュし、85 以上のスレッドがあることがわかります。問題は、dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0) を 50 回連続して呼び出すと、GCD が作成するスレッドが多すぎることでしょうか? gcd がすべてのスレッドを処理し、スレッド数が膨大にならないようにしていると思いましたが、そうでない場合、スレッド数に影響を与える方法はありますか?

4

3 に答える 3

10

カーネルは、グローバル同時キューの既存の GCD ワーカー スレッドのワークユニットがカーネルでかなりの時間ブロックされると、追加のスレッドを作成します (グローバル キューで保留中の作業がある限り)。

これは、アプリケーションが全体的に進行し続けることができるようにするために必要です (たとえば、保留中のブロックの 1 つを実行すると、ブロックされたスレッドがブロック解除される可能性があります)。

ワーカー スレッドがカーネルでブロックされる理由が IO である場合 (例:+[NSData dataWithContentsOfURL:]この例)、最適な解決策は、それらの呼び出しを、ブロックせずにその IO を非同期に実行する API に置き換えることNSURLConnectionです。ファイルシステム IO。

または、カウント ディスパッチ セマフォを使用するなどして、同時ブロック操作の数を手動で制限することもできます。

WWDC 2012 GCD セッションでは、このトピックについて詳しく説明しました。

于 2013-02-05T06:14:11.693 に答える
3

http://developer.apple.com/library/ios/#documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues/OperationQueues.htmlから

並行キュー(グローバルディスパッチキューの一種とも呼ばれます)は、1つ以上のタスクを同時に実行しますが、タスクは、キューに追加された順序で開始されます。現在実行中のタスクは、ディスパッチキューによって管理される個別のスレッドで実行されます。任意の時点で実行されるタスクの正確な数は可変であり、システムの状態によって異なります。

シリアルキュー(プライベートディスパッチキューとも呼ばれます)は、キューに追加された順序で一度に1つのタスクを実行します。現在実行中のタスクは、ディスパッチキューによって管理される個別のスレッド(タスクごとに異なる可能性があります)で実行されます。

すべてのブロックを優先度の高い同時ディスパッチキューにディスパッチする

[NSData dataWithContentsOfURL:URL]

これは同期ブロッキングネットワーク操作であり、デフォルトのGCD動作は、ブロックをできるだけ早く実行するために大量のスレッドを生成することであるように見えます。

にディスパッチする必要がありますDISPATCH_QUEUE_PRIORITY_BACKGROUND。これらのタスクは決して「高優先度」ではありません。画像処理は、空き時間があり、メインスレッドで何も起きていないときに実行する必要があります。

一度に発生するこれらの事柄の数をより細かく制御したい場合は、を使用することを検討することをお勧めしますNSOperation。ブロックを取得して、を使用して操作に埋め込むことができます。NSBlockOperationその後、これらの操作を自分のに送信できますNSOperationQueue。にNSOperationQueueはが- (NSInteger)maxConcurrentOperationCountあり、追加のメリットとして、必要に応じてスケジュール後に操作をキャンセルすることもできます。

于 2013-02-04T12:01:14.303 に答える
1

NSOperationqueueでサポートされている を使用できます。NSURLConnection

また、次のインスタンス メソッドがあります。

- (void)setMaxConcurrentOperationCount:(NSInteger)count
于 2013-02-04T11:49:28.423 に答える