运用 GCD 优化并发网络请求
- 优化方案
- 使用并发队列:通过
dispatch_get_global_queue
获取全局并发队列,将网络请求任务提交到该队列。例如:
dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(globalQueue, ^{
// 网络请求代码
});
- **控制并发数**:如果需要控制同时执行的网络请求数量,可以使用信号量(dispatch_semaphore)。例如,假设只允许同时执行3个网络请求:
dispatch_semaphore_t semaphore = dispatch_semaphore_create(3);
for (int i = 0; i < 10; i++) {
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
dispatch_async(globalQueue, ^{
// 网络请求代码
dispatch_semaphore_signal(semaphore);
});
}
- **利用队列组(dispatch_group)**:当需要在所有网络请求完成后执行一些操作时,可使用队列组。例如:
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
for (int i = 0; i < 5; i++) {
dispatch_group_async(group, globalQueue, ^{
// 网络请求代码
});
}
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
// 所有网络请求完成后执行的代码
});
- 可能遇到的陷阱及解决方案
- 死锁:
- 陷阱:在主线程中同步(dispatch_sync)提交任务到主队列可能会导致死锁。因为主线程正在等待任务完成,而任务又在等待主线程空闲来执行。
- 解决方案:避免在主线程中使用
dispatch_sync
提交任务到主队列。如果需要在主线程执行任务后执行一些操作,可以使用dispatch_async
提交到主队列。
- 资源竞争:
- 陷阱:多个并发网络请求可能会访问和修改共享资源,导致数据不一致。
- 解决方案:使用锁(如
dispatch_mutex
)来保护共享资源。例如:
dispatch_mutex_t mutex = dispatch_mutex_create();
dispatch_async(globalQueue, ^{
dispatch_mutex_lock(mutex);
// 访问和修改共享资源的代码
dispatch_mutex_unlock(mutex);
});
运用 NSOperationQueue 优化并发网络请求
- 优化方案
- 创建操作(NSOperation):可以创建自定义的
NSOperation
子类,在main
方法中实现网络请求逻辑。或者使用NSBlockOperation
,通过addExecutionBlock
添加网络请求块。例如:
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
// 网络请求代码
}];
- **添加操作到队列**:创建`NSOperationQueue`,并将操作添加到队列中。可以设置队列的最大并发数来控制同时执行的网络请求数量。例如:
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
queue.maxConcurrentOperationCount = 3;
[queue addOperation:operation];
- **操作依赖**:当某些网络请求依赖于其他请求的结果时,可以设置操作之间的依赖关系。例如:
NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{
// 第一个网络请求代码
}];
NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{
// 依赖于operation1结果的网络请求代码
}];
[operation2 addDependency:operation1];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperation:operation1];
[queue addOperation:operation2];
- 可能遇到的陷阱及解决方案
- 死锁:
- 陷阱:设置操作依赖关系不当,形成循环依赖可能导致死锁。例如,操作A依赖操作B,操作B又依赖操作A。
- 解决方案:仔细检查操作依赖关系,确保不存在循环依赖。
- 内存管理:
- 陷阱:如果在操作中持有强引用的对象,并且操作执行时间较长,可能导致对象无法释放,引起内存泄漏。
- 解决方案:在操作完成后,及时释放不需要的强引用。可以使用
NSOperation
的completionBlock
来处理清理工作。例如:
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
// 网络请求代码
}];
operation.completionBlock = ^{
// 释放强引用的代码
};