1. 什么是GCD
异步执行任务的技术之一
在GCD之前,cocoa框架提供了NSObject类performSelectorInBackground:withObject
实例方法和performSelectorOnMainThread
实例方法
2. 什么是dispatch_sync和dispatch_async
dispatch_sync函数的“sync”意味着“非同步”,就是将指定的Block“非同步”追加到Dispatch Queue中。dispatch_sync函数不做任何等待。
dispatch_async函数的“async”意味着“同步”,就是将指定的Block“同步”追加到Dispatch Queue中。在追加Block结束之前,dispatch_sync函数会一直等待。等待意味着执行此Block的线程停止了。
3. 什么是Dispatch Queue
执行处理时存在两种Dispatch Queue,
- 一种是等待现在执行中处理的Serial Dispatch Queue
缺点:
(1)过多使用多线程(生成大量的Serial Dispatch Queue),会消耗大量内存,引起大量的上下文切换,大幅度降低系统的响应性能。
(2)多个Serial Dispatch Queue会发生数据竞争 - 另外一种是不等待现在执行中处理的Concurrent Dispatch Queue
注意:
当想并发执行而不发生数据竞争和使用过多线程而导致性能等问题时使用Concurrent Dispatch Queue。
4. 如何创建Dispatch Queue
-
第一种方法是通过GCD的API生成Dispatch Queue
dispatch_queue_create(<#const char * _Nullable label#>, <#dispatch_queue_attr_t _Nullable attr#>)
第一个参数指定Queue名称
推荐使用应用程序ID这种逆序全程域名。该名称在Xcode和Instrument的调试器中作为Dispatch Queue名称表示,也会出现在应用程序崩溃时所生成的CrashLog中
第二个参数创建Dispatch Queue的类型
如果指定为NULL,创建的是Serial Dispatch Queue。要生成Concurrent Dispatch Queue时要指定为DISPATCH_QUEUE_CONCURRENT
-
第二种方法是获取系统标准提供的Dispatch Queue
Main Dispatch Queue
正如其名称含有"Main"一样,是在主线程中执行的Dispatch Queue。因为主线程只有一个,所以Main Dispatch Queue自然就是Serial Dispatch Queue。
Global Dispatch Queue
所有应用程序都能使用的Concurrent Dispatch Queue,没有必要通过dispatch_queue_create函数逐个生成。
另外Global Dispatch Queue有4个执行优先级,分别是高优先级(High Priority)、默认优先级(Default Priority)、低优先级(low Priority)、后台优先级(background Priority)。在向Global Dispatch Queue追加处理时,应选择与处理内容对应的执行优先级的Global Dispatch Queue。
获取方法
/*
* Main Dispatch Queue获取方法
*/
dispatch_queue_t myConcurrentQueue =
dispatch_get_main_queue();
/*
* Global Dispatch Queue (高优先级) 的获取方法
*/
dispatch_queue_t globalDispatchQueueHige =
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
/*
* Global Dispatch Queue (默认优先级) 的获取方法
*/
dispatch_queue_t globalDispatchQueueDefalut =
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
/*
* Global Dispatch Queue (低优先级) 的获取方法
*/
dispatch_queue_t globalDispatchQueuelow =
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0);
/*
* Global Dispatch Queue (后台优先级) 的获取方法
*/
dispatch_queue_t globalDispatchQueuebackground =
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
5. dispatch_after指定时间后执行处理
这里的时间可以是相对时间,例如3秒后执行,也可以是绝对时间,例如指定2100年11月11日11时这一绝对时间,可以作为粗略闹钟功能使用。
注意:
dispatch_after函数并不是在指定时间后执行处理(block),而是指定时候后追加处理到Dispatch Queue中。如果线程本身有大量处理要追加,这个时间延长越厉害。
例子:
// 相对时间
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 3ull * NSEC_PER_SEC);
dispatch_after(time, dispatch_get_main_queue(), ^{
NSLog(@"3 秒后 执行这个");
});
// 绝对时间
//5秒后的时间,可以指定任意绝对时间,例子里只是简单指定比现在晚5秒。
NSDate *furtureDate = [[NSDate alloc] initWithTimeIntervalSinceNow:5];
dispatch_time_t relTime = getDispatchTimeByDate(furtureDate);
dispatch_after(relTime, dispatch_get_main_queue(), ^{
NSLog(@"5 秒后 执行这个");
});
注意:dispatch_walltime函数由POSIX中使用的struct timespec类型
的时间得到dispatch_time_t类型的值。具体装换如下:
dispatch_time_t getDispatchTimeByDate(NSDate *date) {
NSTimeInterval interval;
double second, subsecond;
struct timespec time;
dispatch_time_t milestone;
interval = [date timeIntervalSince1970];
subsecond = modf(interval, &second);
time.tv_sec = second;
time.tv_nsec = subsecond * NSEC_PER_SEC;
milestone = dispatch_walltime(&time, 0);
return milestone;
}
dispatch_after(dispatch_time_t when, dispatch_queue_t _Nonnull queue, ^(void)block)
第一个参数是指定时间dispatch_time_t。该值使用dispatch_time函数或者dispatch_walltime生成。
第二个参数指定要追加的Dispatch Queue。
最后一个参数要执行处理的Block。
6. Dispatch Group
使用场景是在追加到Dispatch Queue中多个处理全部结束后想执行结束处理。
7. dispatch_barrier_queue
使用场景:文件的读取与写入,为了避免发生数据竞争,多个文件的读取操做可以并行执行,但不可以与文件的写入操作并行,文件的写入操作之间只能串行且不能有文件读取操作存在。dispatch_barrier_async函数可以实现高效率的数据库访问和文件访问
网友评论