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. 第二个也可能产生取消问题 - 如果我们有 100 个作业已经在串行队列中等待执行,我们不能一次取消它们。

显而易见且愚蠢的解决方案是用 dispatch_sync 替换敏感的 dispatch_async 方法,但它绝对是我不喜欢的方法。

对于这种情况,推荐的方法是什么?

我希望一个比“使用 NSOperationQueue - 它可以限制并发操作的数量”更聪明的答案确实存在(类似的主题:带有 NSOperationQueueDefaultMaxConcurrentOperationCount 的线程数)。

更新 1:唯一体面的模式是:是将所有 dispatch_async 的块替换为并发队列,并在基于 NSOperationQueue 的并发队列中运行包装在 NSOperations 中的这些块,并设置最大操作限制(在我的情况下,可能还设置了最大操作限制AFNetworking 在其中运行所有操作的基于 NSOperationQueue 的队列)。

4

2 回答 2

7

您正在启动太多网络请求。AFAIK 它没有在任何地方记录,但您最多可以同时运行 6 个网络连接(考虑到RFC 2616 8.1.4第 6 段,这是一个合理的数字)。之后你获得锁定,GCD 补偿创建更多线程,顺便说一下,每个线程都有一个 512KB 的堆栈空间,每个页面都按需分配。所以是的,为此使用 NSOperation。我用它来排队网络请求,在再次请求相同对象时增加优先级,如果用户离开,则暂停并序列化到磁盘。我还监控网络请求的速度(以字节/时间为单位)并更改并发操作的数量。

于 2013-01-11T08:13:21.657 回答
1

虽然我没有从您的示例中看到您正在创建“太多”后台线程的确切位置,但我将尝试回答如何控制每个队列的确切线程数的问题。苹果的文档说:

并发队列(也称为全局调度队列的一种)同时执行一个或多个任务,但任务仍然按照它们添加到队列的顺序启动。当前正在执行的任务在由调度队列管理的不同线程上运行。在任何给定点执行的任务的确切数量是可变的,并且取决于系统条件。

虽然您现在(从 iOS5 开始)可以手动创建并发队列,但无法控制这样一个队列将同时运行多少作业。操作系统会自动平衡负载。如果出于某种原因,您不希望这样,例如,您可以手动创建一组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 回答