在我的应用程序中,我在 NSOperationQueue 中执行 10 个异步 NSURLConnections 作为 NSInitationOperations。为了防止每个操作在连接有机会完成之前返回,我调用 CFRunLoopRun() ,如下所示:
- (void)connectInBackground:(NSURLRequest*)URLRequest {
TTURLConnection* connection = [[TTURLConnection alloc] initWithRequest:URLRequest delegate:self];
// Prevent the thread from exiting while the asynchronous connection completes the work. Delegate methods will
// continue the run loop when the connection is finished.
CFRunLoopRun();
[connection release];
}
连接完成后,最终的连接委托选择器调用 CFRunLoopStop(CFRunLoopGetCurrent()) 来恢复 connectInBackground() 中的执行,使其正常返回:
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
TTURLConnection* ttConnection = (TTURLConnection*)connection;
...
// Resume execution where CFRunLoopRun() was called.
CFRunLoopStop(CFRunLoopGetCurrent());
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
TTURLConnection* ttConnection = (TTURLConnection*)connection;
...
// Resume execution where CFRunLoopRun() was called.
CFRunLoopStop(CFRunLoopGetCurrent());
}
这工作得很好,而且是线程安全的,因为我将每个连接的响应和数据作为实例变量捆绑在 TTURLConnection 子类中。
NSOperationQueue 声称将其最大并发操作数保留为 NSOperationQueueDefaultMaxConcurrentOperationCount 允许它动态调整操作数,但是,在这种情况下,它始终认为 1 就足够了。因为这不是我想要的,所以我将最大数量更改为 10,现在它已经严重拖拉了。
这样做的问题是这些线程(在 SpringBoard 和 DTMobileIS 的帮助下)消耗了所有可用的 CPU 时间并导致主线程变得潜在。换句话说,一旦 CPU 利用率达到 100%,主线程处理 UI 事件的速度就不会达到维持流畅 UI 所需的速度。具体来说,表视图滚动变得不稳定。
Process Name % CPU
SpringBoard 45.1
MyApp 33.8
DTMobileIS 12.2
...
当用户与屏幕交互或表格滚动时,主线程的优先级变为 1.0(最高可能),并且其运行循环模式变为 UIEventTrackingMode。默认情况下,每个操作的线程的优先级都是 0.5,并且异步连接在 NSDefaultRunLoopMode 中运行。由于我对线程及其运行循环如何根据优先级和模式进行交互的理解有限,我被难住了。
有没有一种方法可以安全地消耗应用程序后台线程中的所有可用 CPU 时间,同时仍然保证为其主线程提供所需的 CPU 时间?也许通过强制主线程根据需要运行? (我认为线程优先级会解决这个问题。)
12/23 更新:我终于开始掌握 CPU 采样器,并找到了 UI 变得不稳定的大部分原因。首先,我的软件正在调用一个具有互斥信号量的库。这些锁会在短时间内阻塞主线程,导致滚动稍微跳过。
此外,我发现一些昂贵的 NSFileManager 调用和 md5 哈希函数需要花费太多时间来运行。过于频繁地分配大对象会导致主线程中出现一些其他性能问题。
我已经开始解决这些问题并且性能已经比以前好很多了。我有 5 个同时连接,并且滚动很流畅,但我还有更多工作要做。我计划编写一份关于如何使用 CPU Sampler 来检测和修复影响主线程性能的问题的指南。感谢迄今为止的评论,它们很有帮助!
2010 年 1 月 14 日更新:在达到可接受的性能后,我开始意识到 CFNetwork 框架偶尔会泄漏内存。 CFNetwork 内部也随机(但是很少)出现异常!我尽了一切努力来避免这些问题,但没有任何效果。我非常确定这些问题是由于 NSURLConnection 本身的缺陷造成的。我编写的测试程序除了练习 NSURLConnection 之外什么也没做,但它们仍然崩溃和泄漏。
最终我将 NSURLConnection 替换为ASIHTTP请求撞击声完全停止了。 CF网络almost永远不会泄漏,但是,在解析 DNS 名称时仍然会发生一种非常罕见的泄漏。我现在已经很满意了。希望这些信息可以为您节省一些时间!