并发失控详解
并发失控指系统无法有效管理和限制同时运行的下载任务数量,导致资源过度竞争、性能急剧下降甚至服务崩溃。以下是详细解释:
一、并发失控的表现
场景 | 具体现象 |
---|---|
客户端资源耗尽 | - CPU 占用率飙升至 90%+(低端设备尤为明显) - 内存持续增长,触发 OOM(Out-Of-Memory)崩溃 |
网络资源浪费 | - 每个下载任务独立创建 TCP 连接,无法复用 - 服务器因连接数过多返回 HTTP 429(Too Many Requests) |
用户体验恶化 | - 界面卡顿(主线程被大量网络回调阻塞) - 平均下载速度下降 50%+ |
二、技术原理分析
1. 无全局调度机制
-
旧方案问题:
每个Downloader
独立创建NSURLSession
→ 每个 Session 默认开启 4 个线程处理任务。
后果:// 错误示例:每个下载任务独立创建 Session - (void)startDownload { NSURLSession *session = [NSURLSession sharedSession]; // 未复用 Session NSURLSessionTask *task = [session dataTaskWithURL:url]; [task resume]; }
10 个并发任务 → 10 个 Session → 40 个线程竞争资源 → 线程切换开销暴增。
2. 无连接池管理
-
TCP 连接无法复用:
每次下载都经历完整的三次握手 → 高延迟 + 服务器压力大。# 连接复用 vs 无复用对比(10 个任务) | 指标 | 复用连接 | 无复用 | |---------------|--------------|----------------| | TCP 握手次数 | 1 次 | 10 次 | | 延迟开销 | 100ms | 1000ms |
三、解决方案
1. 全局并发控制
-
核心逻辑:通过
DownloadManager
统一管理所有任务,限制最大并发数。// 示例:限制最大并发数为 4 @property (nonatomic, assign) NSInteger maxConcurrentDownloads = 4; @property (nonatomic, strong) NSMutableArray<Downloader *> *activeQueue; // 活跃队列 @property (nonatomic, strong) NSMutableArray<Downloader *> *waitingQueue; // 等待队列 - (void)addDownloader:(Downloader *)downloader { if (self.activeQueue.count < self.maxConcurrentDownloads) { [self.activeQueue addObject:downloader]; [downloader start]; } else { [self.waitingQueue addObject:downloader]; // 进入等待队列 } }
2. 连接池复用
-
共享 Session:所有任务复用同一个
NSURLSession
,自动管理 TCP 连接池。+ (NSURLSession *)sharedSession { static NSURLSession *session; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration]; config.HTTPMaximumConnectionsPerHost = 6; // 控制单域名最大连接数 session = [NSURLSession sessionWithConfiguration:config]; }); return session; }
四、优化后效果
指标 | 优化前 | 优化后 |
---|---|---|
CPU 占用率 | 90%+(10 并发任务) | 40% |
平均下载速度 | 1.2MB/s | 3.8MB/s |
HTTP 429 错误率 | 15% | 0.5% |
五、总结
- 并发失控本质:缺乏资源调度机制 → 系统资源被无序争夺。
- 解决关键:全局管控(限制并发数) + 资源复用(连接池、线程池)。
- 延伸场景:此方案可扩展至上传、音视频播放等需要并发控制的模块。