通过 GCD 提供的方法来将一些需要耗时操作放到非主线程上做,使得 App 能够运行的更加流畅响应更快。但是使用 GCD 时需要注意避免可能引起线程爆炸和死锁的情况,还有非主线程处理任务也不是万能的,如果一个处理需要消耗大量内存或者大量CPU操作 GCD 也没法帮你,只能通过将处理进行拆解分步骤分时间进行处理才比较妥当。
一、dispatch_block_t应用
1、dispatch_block_t
初始化
1> dispatch_block_create
dispatch_block_t dispatch_block_create(dispatch_block_flags_t flags, dispatch_block_t block);
flags
的类型为 dispatch_block_flags_t
的枚举,用于设置 block 的标记,定义如下:
DISPATCH_ENUM(dispatch_block_flags, unsigned long,
DISPATCH_BLOCK_BARRIER = 0x1,
DISPATCH_BLOCK_DETACHED = 0x2,
DISPATCH_BLOCK_ASSIGN_CURRENT = 0x4,
DISPATCH_BLOCK_NO_QOS_CLASS = 0x8,
DISPATCH_BLOCK_INHERIT_QOS_CLASS = 0x10,
DISPATCH_BLOCK_ENFORCE_QOS_CLASS = 0x20,
);
2> dispatch_block_create_with_qos_class
dispatch_block_t dispatch_block_create_with_qos_class(dispatch_block_flags_t flags,
dispatch_qos_class_t qos_class, int relative_priority,
dispatch_block_t block);
这种方式在创建 block 的同时可以指定了相应的优先级。
dispatch_qos_class_t
是 qos_class_t
的别名,qos_class_t
是一种枚举,有以下类型:
-
QOS_CLASS_USER_INTERACTIVE
:user interactive 等级表示任务需要被立即执行,用来在响应事件之后更新 UI,来提供好的用户体验。这个等级最好保持小规模。 -
QOS_CLASS_USER_INITIATED
:user initiated 等级表示任务由 UI 发起异步执行。适用场景是需要及时结果同时又可以继续交互的时候。 -
QOS_CLASS_DEFAULT
:default 默认优先级。 -
QOS_CLASS_UTILITY
:utility 等级表示需要长时间运行的任务,伴有用户可见进度指示器。经常会用来做计算,I/O,网络,持续的数据填充等任务。这个任务节能。 -
QOS_CLASS_BACKGROUND
:background 等级表示用户不会察觉的任务,使用它来处理预加载,或者不需要用户交互和对时间不敏感的任务。 -
QOS_CLASS_UNSPECIFIED
:unspecified 未指明
dispatch_queue_t concurrentQuene = dispatch_queue_create("concurrentQuene", DISPATCH_QUEUE_CONCURRENT);
dispatch_block_t block = dispatch_block_create(0, ^{
NSLog(@"normal do some thing...");
});
dispatch_async(concurrentQuene, block);
//
dispatch_block_t qosBlock = dispatch_block_create_with_qos_class(0, QOS_CLASS_DEFAULT, 0, ^{
NSLog(@"qos do some thing...");
});
dispatch_async(concurrentQuene, qosBlock);
2、监听 block 执行结束
1> dispatch_block_wait
long dispatch_block_wait(dispatch_block_t block, dispatch_time_t timeout);
注意:因为
dispatch_block_wait
会阻塞当前线程,所以不应该放在主线程中调用。
dispatch_queue_t concurrentQuene = dispatch_queue_create("concurrentQuene", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(concurrentQuene, ^{
dispatch_queue_t allTasksQueue = dispatch_queue_create("allTasksQueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_block_t block = dispatch_block_create(0, ^{
NSLog(@"开始执行");
[NSThread sleepForTimeInterval:3];
NSLog(@"结束执行");
});
dispatch_async(allTasksQueue, block);
// 等待时长,10s 之后超时
dispatch_time_t timeout = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10 * NSEC_PER_SEC));
long resutl = dispatch_block_wait(block, timeout);
if (resutl == 0) {
NSLog(@"执行成功");
} else {
NSLog(@"执行超时");
}
});
2> dispatch_block_notify
void dispatch_block_notify(dispatch_block_t block,
dispatch_queue_t queue,
dispatch_block_t notification_block);
该函数接收三个参数,第一个参数是需要监视的 block,第二个参数是监听的 block 执行结束之后要提交执行的队列
queue
,第三个参数是待加入到队列中的 block。 和dispatch_block_wait
的不同之处在于:dispatch_block_notify
函数不会阻塞当前线程。
NSLog(@"---- 开始设置任务 ----");
dispatch_queue_t serialQueue = dispatch_queue_create("com.fyf.serialqueue", DISPATCH_QUEUE_SERIAL);
// 耗时任务
dispatch_block_t taskBlock = dispatch_block_create(0, ^{
NSLog(@"开始耗时任务");
[NSThread sleepForTimeInterval:2.f];
NSLog(@"完成耗时任务");
});
dispatch_async(serialQueue, taskBlock);
// 更新 UI
dispatch_block_t refreshUI = dispatch_block_create(0, ^{
NSLog(@"更新 UI");
});
// 设置监听
dispatch_block_notify(taskBlock, dispatch_get_main_queue(), refreshUI);
NSLog(@"---- 完成设置任务 ----");
3、取消block
dispatch_block_cancel
void dispatch_block_cancel(dispatch_block_t block);
取消操作使将来执行 dispatch block 立即返回,但是对已经在执行的 dispatch block 没有任何影响。
二、性能优化相关应用
1> 异步处理事件
2> 需要耗时长的任务
GCD 的 block 通过 dispatch_block_create_with_qos_class 方法指定队列的 QoS 为 QOS_CLASS_UTILITY。这种 QoS 系统会针对大的计算,I/O,网络以及复杂数据处理做电量优化。
3> 避免线程爆炸
举个例子,下面的写法就比较危险,可能会造成线程爆炸和死锁:
for (int i = 0; i < 999; i++) {
dispatch_async(q, ^{…});
}
dispatch_barrier_sync(q, ^{});
1、使用串行队列
2、使用 NSOperationQueues
的并发限制方法NSOperationQueue.maxConcurrentOperationCount
3、使用GCD信号量dispatch_semaphore
控制线程最大并发
4> I/O 性能优化
一般出发点:
1、将零碎的内容作为一个整体进行写入 ;
2、使用合适的 I/O 操作 API ;
3、使用合适的线程 ;
4、使用 NSCache 做缓存能够减少 I/O;
参考链接:
深入剖析 iOS 性能优化
GCD 之任务操作(Dispatch Block)