4

アプリが実行しているスレッドの数を制御してバランスをとる方法、スレッドの制限に達したためにアプリがブロックされないようにスレッドの数を制限する方法は?

ここで私は次の可能な答えを見ました:「メイン同時キュー(dispatch_get_global_queue)はスレッドの数を自動的に管理します」これは次の理由で好きではありません:

次のパターンを考えてみましょう(私の実際のアプリには、より単純な例とより複雑な例の両方があります)。

dispatch_queue_t defaultBackgroundQueue() {
    return dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
}

dispatch_queue_t databaseQueue() {
    dispatch_queue_create("Database private queue", 0);
}

dispatch_async(defaultBackgroundQueue(), ^{
    [AFNetworkingAsynchronousRequestWithCompletionHandler:^(data){
        dispatch_async(databaseQueue(), ^{
            // data is about 100-200 elements to parse
            for (el in data) {

            }

            maybe more AFNetworking requests and/or processing in other queues or

            dispatch_async(dispatch_get_main_queue(), ^{
                // At last! We can do something on UI.
            });
        });
    }];
});

この設計は、次のような状況につながることがよくあります。

  1. スレッド制限に達したためにアプリがロックされています(> 64など)
  2. 低速で狭いキューは、多数の保留中のジョブに圧倒される可能性があります。
  3. 2番目の問題もキャンセルの問題を引き起こす可能性があります。シリアルキューで実行を待機しているジョブが100個ある場合、それらを一度にキャンセルすることはできません。

明白でばかげた解決策は、機密性の高いdispatch_asyncメソッドをdispatch_syncに置き換えることですが、それは間違いなく私が好きではないものです。

このような状況で推奨されるアプローチは何ですか?

「NSOperationQueueを使用する-同時操作の数を制限できる」よりも賢い答えが存在することを願っています(同様のトピック:NSOperationQueueDefaultMaxConcurrentOperationCountを持つスレッドの数)。

更新1:唯一の適切なパターンは次のとおりです:最大操作制限が設定されたNSOperationQueueベースの同時キューでNSOperationsにラップされたこれらのブロックを実行して同時キューにブロックのすべてのdispatch_asyncを置き換えることです(私の場合は最大操作制限も設定されていますAFNetworkingがすべての操作を実行するNSOperationQueueベースのキュー)。

4

2 に答える 2

7

開始するネットワーク リクエストが多すぎます。私の知る限り、どこにも文書化されていませんが、最大 6 つの同時ネットワーク接続を実行できます (これは、RFC 2616 8.1.4のパラグラフ 6 を考慮すると適切な数です)。その後、ロックが発生し、GCD は追加のスレッドの作成を補償します。ちなみに、各スレッドには 512KB のスタック スペースがあり、ページはオンデマンドで割り当てられます。そうです、これには NSOperation を使用してください。これを使用して、ネットワーク要求をキューに入れ、同じオブジェクトが再度要求されたときに優先度を上げ、ユーザーが離れた場合に一時停止してディスクにシリアル化します。また、ネットワーク要求の速度をバイト/時間で監視し、同時操作の数を変更します。

于 2013-01-11T08:13:21.657 に答える
1

「多すぎる」バックグラウンドスレッドを正確に作成している例からはわかりませんが、キューごとのスレッドの正確な数を制御する方法の質問に答えようとします。Apple のドキュメントには次のように書かれています。

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

(iOS5 以降) 同時キューを手動で作成できるようになりましたが、そのようなキューによって同時に実行されるジョブの数を制御する方法はありません。OS が自動的に負荷を分散します。なんらかの理由でそれを望まない場合は、たとえば一連のn 個のシリアル キューを手動で作成し、新しいジョブをn 個のキューのいずれかにランダムにディスパッチできます。

NSArray *queues = @[dispatch_queue_create("com.myapp.queue1", 0),dispatch_queue_create("com.myapp.queue2", 0),dispatch_queue_create("com.myapp.queue3", 0)];
NSUInteger randQueue = arc4random() % [queues count];
dispatch_async([queues objectAtIndex:randQueue], ^{
    NSLog(@"Do something");
});
randQueue = arc4random() % [queues count];
dispatch_async([queues objectAtIndex:randQueue], ^{
    NSLog(@"Do something else");
});

私は決してこの設計を支持しているわけではありません。同時キューはシステム リソースのバランスを取るのに非常に優れていると思います。しかし、あなたが尋ねたので、これは実行可能なアプローチだと思います。

于 2013-02-01T15:52:47.060 に答える