【发布时间】:2013-01-11 04:50:48
【问题描述】:
如何控制和平衡我的应用正在执行的线程数量,如何限制它们的数量以避免应用因为达到线程限制而阻塞?
在这里,我看到了以下可能的答案:“主并发队列(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.
});
});
}];
});
这种设计经常导致以下情况:
- 应用因线程数达到限制而被锁定(类似于 > 64)
- 较慢且因此较窄的队列可能会因大量挂起的作业而不堪重负。
- 第二个也可能产生取消问题 - 如果我们有 100 个作业已经在串行队列中等待执行,我们无法立即取消它们。
显而易见且愚蠢的解决方案是将敏感的 dispatch_async 方法替换为 dispatch_sync,但它绝对是我不喜欢的方法。
对于这种情况,推荐的方法是什么?
我希望确实存在一个比“使用 NSOperationQueue - 它可以限制并发操作的数量”更聪明的答案(类似主题:Number of threads with NSOperationQueueDefaultMaxConcurrentOperationCount)。
更新 1:唯一体面的模式是:是将所有 dispatch_async 块替换为并发队列,并在基于 NSOperationQueue 的并发队列中运行包装在 NSOperations 中的这些块,并设置最大操作限制(在我的情况下,也可能设置一个最大值AFNetworking 在其中运行所有操作的基于 NSOperationQueue 的队列的操作限制)。
【问题讨论】:
-
“应用被锁定”是什么意思?你总会有一些线程在执行,只要有一些线程在执行,你的应用就会取得进展。
-
“不知所措”是什么意思?如果您提交作业的速度快于 CPU 执行它们的速度,那么无论它们有多宽,队列都会积压。
-
使用您使用的方法(或 NSOperation,就此而言),显式线程的创建和触发超出了范围。我不一定同意问题如您所想 - 但是,在回答这个问题时,您可以显式控制创建的线程数量的唯一方法是手动创建它们,例如使用 NSThread。
-
只需加上我的 0.05 美元:外部的
dispatch_async(defaultBackgroundQueue(), ^{...}是不必要的,AFNetworking 有自己的队列,用于执行 HTTP 请求。启动该请求的过程非常快,没有理由将其包装在异步块中。
标签: ios objective-c concurrency