GCD属于系统级的线程管理,在Dispatch queue中执行任务,GCD中的FIFO队列称为dispatch queue,用来保证先进来的任务先得到执行。
概要
(1)和operation queue一样都是基于队列的并发编程API,通过集中管理协同工作的线程池。
(2)公开的5个不同优先级队列:运行于主线程的main queue,3个不同优先级(High Priority Queue, Default Priority Queue,Low Priority Queue)全局队列,以及一个优先级更低的后台队列Background Priority Queue(用于IO)。
(3)可创建自定义队列:串行或者并行队列。自定义一般放在Default Priority Queue和Main Queue里。
相关操作方法
创建队列
dispatch_queue_t serialQueue = dispatch_queue_create("serialqueue", DISPATCH_QUEUE_SERIAL);//串行队列
dispatch_queue_t currentQueue = dispatch_queue_create("currentqueue", DISPATCH_QUEUE_CONCURRENT);//并行队列
dispatch_queue_t mainQueue = dispatch_get_main_queue();//获取当前主队列
dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);//获取全局并发队列
//async : 串行队列异步调用不会开辟新线程,在主线程串行执行。
dispatch_async(serialQueue, ^{
NSLog(@"串行队列异步线程1%@",[NSThread currentThread]);
});
dispatch_async(serialQueue, ^{
NSLog(@"串行队列异步线程2%@",[NSThread currentThread]);
});
//async : 并行队列异步调用开辟新线程,并发执行任务。
dispatch_async(currentQueue, ^{
NSLog(@"并行队列异步线程1%@",[NSThread currentThread]);
});
dispatch_async(currentQueue, ^{
NSLog(@"并行队列异步线程2%@",[NSThread currentThread]);
});
//sync 主队列同步线程崩溃
dispatch_sync(mainQueue, ^{
NSLog(@"主队列同步1%@",[NSThread currentThread]);
});
dispatch_sync(mainQueue, ^{
NSLog(@"主队列同步2%@",[NSThread currentThread]);
});
//同步串行队列不会开辟新线程,串行执行
dispatch_sync(serialQueue, ^{
NSLog(@"串行队列同步1%@",[NSThread currentThread]);
});
dispatch_sync(serialQueue, ^{
NSLog(@"串行队列同步2%@",[NSThread currentThread]);
});
//同步并行队列不开新线程串行执行
dispatch_sync(currentQueue, ^{
NSLog(@"并行队列同步1%@",[NSThread currentThread]);
});
dispatch_sync(currentQueue, ^{
NSLog(@"并行队列同步2%@",[NSThread currentThread]);
});
GCD group把相关的任务归并到一个组内来执行,通过监听组内所有任务的执行情况来做相应处理。当group里所有事件都完成GCD API有两种方式发送通知,第一种是dispatch_group_wait,会阻塞当前进程,等所有任务都完成或等待超时。第二种方法是使用dispatch_group_notify,异步执行闭包,不会阻塞。
dispatch_group_t group = dispatch_group_create();//创建组
dispatch_group_enter(group);//用于添加对应任务组中的未执行完毕的任务数,执行一次,未执行完毕的任务数加1,当未执行完毕任务数为0的时候结束组。
dispatch_group_async(group, serialQueue, ^{
NSLog(@"group start%@",[NSThread currentThread]);
dispatch_async(currentQueue, ^{
sleep(1);
NSLog(@"group do%@",[NSThread currentThread]);
dispatch_group_leave(group);//用于减少任务组中的未执行完毕的任务数,执行一次,未执行完毕的任务数减1,dispatch_group_enter和dispatch_group_leave要匹配,不然系统会认为group任务没有执行完毕。
});
});
dispatch_group_notify(group, serialQueue, ^{
NSLog(@"group finish%@",[NSThread currentThread]);
});//待任务组执行完毕时调用,不会阻塞当前线程
Dispatch Semaphore使用dispatch_semaphore_signal加1dispatch_semaphore_wait减1,为0时等待的设置方式来达到线程同步的目的和同步锁一样能够解决资源抢占的问题。
static dispatch_semaphore_t semaphore;
static dispatch_once_t onceToken;
NSUInteger limitSemaphoreCount = 3;
//专门控制并发等待的线程
static dispatch_queue_t receiverQueue;
dispatch_once(&onceToken, ^{//dispatch_once保证只运行一次
//创建信号量
semaphore = dispatch_semaphore_create(limitSemaphoreCount);
receiverQueue = dispatch_queue_create("receiver", DISPATCH_QUEUE_SERIAL);
});
for (int i=0; i<10; i++) {
dispatch_async(currentQueue, ^{
NSLog(@"wait begin");
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
NSLog(@"wait after");
dispatch_async(receiverQueue, ^{
//在该工作队列完成后释放信号量
NSLog(@"释放信号量%@ semaphore=%@",[NSThread currentThread],semaphore);
dispatch_semaphore_signal(semaphore);
});
});
}
dispatch_after延后执行
dispatch_time_t delayTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t) 1 * NSEC_PER_SEC);
NSLog(@"time = %f",[NSDate timeIntervalSinceReferenceDate]);
dispatch_after(delayTime, dispatch_get_main_queue(), ^{
NSLog(@"time = %f",[NSDate timeIntervalSinceReferenceDate]);
});
dispatch_apply类似for循环,将一个block提交给调度队列进行多次调用。
dispatch_async(currentQueue, ^{
dispatch_apply(10, currentQueue, ^(size_t index) {
NSLog(@"index= %zu",index);
});
NSLog(@"end finish async");
});
NSLog(@"finish");
Dispatch IO 文件操作,对于大数据的文件采取分片读取然后再合并,比单线程读取快速。
//dispatch_io_create:创建dispatch io
//dispatch_io_set_low_water:指定切割文件大小
//dispatch_io_read:读取切割的文件然后合并。
NSString *desktop = @"xxx/.../xxx";
NSString *path = [desktop stringByAppendingPathComponent:@"main.m"];
dispatch_queue_t queue = dispatch_queue_create("queue", NULL);//当设置为并行队列时在读取文件时实际还是串行
dispatch_fd_t fd = open(path.UTF8String, O_RDONLY, 0);
dispatch_io_t io = dispatch_io_create(DISPATCH_IO_STREAM, fd, queue, ^(int error) {
close(fd);
});
size_t water = 1024*1024;
dispatch_io_set_low_water(io, water);
dispatch_io_set_high_water(io, water);
long long fileSize = [[NSFileManager defaultManager] attributesOfItemAtPath:path error:nil].fileSize;
NSMutableData *totalData = [[NSMutableData alloc] init];
dispatch_io_read(io, 0, fileSize, queue, ^(bool done, dispatch_data_t _Nullable data, int error) {
if (error == 0) {
size_t len = dispatch_data_get_size(data);
if (len > 0) {
[totalData appendData:(NSData *)data];
}
}
if (done) {
NSString *str = [[NSString alloc] initWithData:totalData encoding:NSUTF8StringEncoding];
NSLog(@"%@", str);
}
});
Dispatch Source 用GCD监视进程,用于监听系统的底层对象,比如文件描述符,Mach端口,信号量等。主要处理的事件如下表
方法 | 说明 |
---|---|
DISPATCH_SOURCE_TYPE_DATA_ADD | 自定义的事件,变量增加 |
DISPATCH_SOURCE_TYPE_DATA_OR | 自定义的事件,数据OR |
DISPATCH_SOURCE_TYPE_MACH_SEND | Mach端口发送 |
DISPATCH_SOURCE_TYPE_MACH_RECV | Mach端口接收 |
DISPATCH_SOURCE_TYPE_MEMORYPRESSURE | 内存情况 |
DISPATCH_SOURCE_TYPE_PROC | 进程监听,如进程的退出、创建一个或更多的子线程、进程收到UNIX信号 |
DISPATCH_SOURCE_TYPE_READ | IO操作,如对文件的操作、socket操作的读响应 |
DISPATCH_SOURCE_TYPE_SIGNAL | 接收到UNIX信号时响应 |
DISPATCH_SOURCE_TYPE_TIMER | 定时器 |
DISPATCH_SOURCE_TYPE_VNODE | 文件系统变化 |
DISPATCH_SOURCE_TYPE_WRITE | IO操作,如对文件的操作、socket操作的写响应 |
//dispatch_source_create:创建dispatch source,创建后会处于挂起状态进行事件接收,需要设置事件处理handler进行事件处理。
//dispatch_source_set_event_handler:设置事件处理handler
//dispatch_source_set_cancel_handler:事件取消handler,就是在dispatch source释放前做些清理的事。
//dispatch_source_cancel:关闭dispatch source,设置的事件处理handler不会被执行,已经执行的事件handler不会取消。
//创建source,以DISPATCH_SOURCE_TYPE_DATA_ADD的方式进行累加,而DISPATCH_SOURCE_TYPE_DATA_OR是对结果进行二进制或运算
dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_ADD, 0, 0, dispatch_get_main_queue());
//事件触发后执行的句柄
dispatch_source_set_event_handler(source,^{
NSLog(@"监听函数:%lu",dispatch_source_get_data(source));
});
//开启source
dispatch_resume(source);
dispatch_queue_t myqueue =dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(myqueue, ^ {
for(int i = 1; i <= 4; i ++){
NSLog(@"~~~~~~~~~~~~~~%d", i);
//触发事件,向source发送事件,这里i不能为0,否则触发不了事件
dispatch_source_merge_data(source,i);
//当Interval的事件越长,则每次的句柄都会触发
//[NSThread sleepForTimeInterval:0.0001];
}
});