简介
- GCD是苹果公司为多核的并行运算提出的解决方案
- GCD会自动利用更多的CPU内核(比如双核、四核)
- GCD会自动管理线程的生命周期(创建线程、调度任务、销毁线程)
- GCD是纯C语言实现的,提供了非常多强大的函数
核心概念
GCD中有两个核心概念:
- 任务:执行什么操作
- 队列:用来存放任务
GCD的使用步骤
- 指定任务,确定想做的事情
- 将任务添加到队列中,GCD会自动将队列中的任务取出来放到对应的线程中执行。队列的取出遵循队列的FIFO原则:先进先出,后进后出
执行任务
GCD中有两个可以用来执行任务的函数
- 用同步的方式执行任务:只能在当前线程中执行,不会开其他线程
//queue:队列;block:任务
void dispatch_sync(dispatch_queue_t queue,dispatch_block_t block);
- 用异步的方法执行任务:可以在新的线程中执行任务,具备开启新线程的能力
//queue:队列;block:任务
void dispatch_async(dispatch_queue_t queue,dispatch_block_t block);
队列的类型
GCD中的队列可以分为两大类型:
-
并发队列(concurrent dispatch queue):可以让队列任务并发(同时)执行(自动开启多个线程同时执行任务),并发功能只有在异步函数(dispatch_asyns)中才有效。
-
GCD默认已经提供了全局的并发队列,提供整个应用使用,不需要手动创建。
dispatch_queue_t dispatch_get_global_queue(dispatch_queue_t priority,unsigned long flags); //priority:队列的优先级,flags:此参数暂时没有使用,传0即可
-
-
串行队列(serial dispatch queue):让任务一个接着一个地执行(一个任务执行完毕后,在执行下一个任务)。GCD有两种方式获得串行队列。
- 使用
dispatch_queue_create
函数手动创建串行队列
dispatch_queue_t dispatch_queue_create(const char *label,dispatch_queue_create_attr_t attr); //label:队列名称,attr:队列属性,一般用NULL即可
- 使用主队列(跟主线程相关的队列):主队列是GCD中的自带的一种特殊的串行队列,放在主队列中的任务,都会放到主线程中执行。
dispatch_queue_t dispatch_get_main_queue(void);
*注意*: 1. //主队列(添加到主队列中的任务,都会自动添加到主线程中执行) dispatch_queue_t queue = dispatch_get_main_queue(); 2. //添加任务到主队列中异步执行,该异步功能失效 dispatch_async(queue,^{任务}); 3. //添加任务到主队列中同步执行,改同步功能会卡死 Dispatch_sync(queue,^{任务});
- 使用
总结
-
同步和异步主要影响能不能开启新的线程:同步在当前线程中执行任务,不具备别开启新线程的能力;异步能在新线程中执行任务,具备开启新线程的能力
dispatch_sync: 同步,不具备开启线程的能力
dispatch_async:异步,具备开启线程的能力
-
并发和串行主要影响任务的执行方式:并发是多个任务同时执行;串行是一个执行完毕后,在执行下一个任务。
//获得全局的并发队列 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0); //创建一个串行队列 dispatch_queue_t queue = dispatch_queue_create("name.queue",NULL); //主队列(添加到主队列中的任务,都会自动方法主线程中执行) dispatch_queue_t queue = dispatch_get_main_queue();
使用例子
- 同步函数+主队列
-(void)syncMain{
NSLog(@"begin");
dispatch_queue_t queue = dispatch_get_main_queue();
dispatch_sync(queue,^{
NSLog(@"1---%@",[NSThread currentThread]);
});
dispatch_sync(queue,^{
NSLog(@"2---%@",[NSThread currentThread]);
});
dispatch_sync(queue,^{
NSLog(@"3---%@",[NSThread currentThread]);
});
NSLog(@"end");
//注意:使用sync函数往当前队列中添加任务,会卡住当前的串行队列,除了begin其他都不会被打印。
}
- 异步函数+主队列
- (void)asyncMain
{
dispatch_queue_t queue = dispatch_get_main_queue();
dispatch_async(queue, ^{
NSLog(@"1-----%@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"2-----%@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"3-----%@", [NSThread currentThread]);
});
//注意:不会开启新线程。只会在主队列中执行,失去了异步函数的功能。
}
- 同步函数+串行队列
-(void)syncSerial{
dispatch_queue_t queue = dispatch_queue_create("com.queue",DISPATCH_QUEUE_SERIAL);
dispatch_sync(queue,^{
NSLog(@"1---%@",[NSThread currentThread]);
})
dispatch_sync(queue,^{
NSLog(@"2---%@",[NSThread currentThread]);
})
dispatch_sync(queue,^{
NSLog(@"3---%@",[NSThread currentThread]);
})
//注意:不会开启新的线程,在当前线程执行任务。任务是串行的,执行完一个任务,再执行下一个任务
}
- 异步函数+串行队列
- (void)asyncSerial
{
dispatch_queue_t queue = dispatch_queue_create("com.queue", DISPATCH_QUEUE_SERIAL);
dispatch_async(queue, ^{
NSLog(@"1-----%@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"2-----%@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"3-----%@", [NSThread currentThread]);
});
注意:会开启新的线程,但是任务是串行的,执行完一个任务,再执行下一个任务
}
- 同步函数+并发队列
- (void)syncConcurrent
{
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_sync(queue, ^{
NSLog(@"1-----%@", [NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"2-----%@", [NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"3-----%@", [NSThread currentThread]);
});
//注意:不会开启新的线程。串行执行任务。
}
- 异步函数+并发队列:可以同时开启多条线程,是最常用的方式
- (void)asyncConcurrent
{
// 1.获得全局的并发队列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// 2.将任务加入队列
dispatch_async(queue, ^{
for (NSInteger i = 0; i<10; i++) {
NSLog(@"1-----%@", [NSThread currentThread]);
}
});
dispatch_async(queue, ^{
for (NSInteger i = 0; i<10; i++) {
NSLog(@"2-----%@", [NSThread currentThread]);
}
});
dispatch_async(queue, ^{
for (NSInteger i = 0; i<10; i++) {
NSLog(@"3-----%@", [NSThread currentThread]);
}
});
各种队列的执行效果
全局并发队列 | 手动创建串行队列 | 主队列(串行队列) | |
---|---|---|---|
同步(sync) | 不会开启新线程串行执行任务 | 没有开启新线程串行执行任务 | 没有开启新线程串行执行任务会卡死 |
异步(async) | 有开启新线程并发执行任务 | 有开启新线程串行执行任务 | 没有开启新线程串行,执行任务 |
GCD的其他用法
用法一
// 作用:在并行队列中,等待前面的所有并行操作完成,然后执行dispatch_barrier_async中的操作,然后恢复原有执行状态,继续并行执行
void dispatch_barrier_async(dispatch_queue_t queue,dispatch_block_t block);
用法二
//作用:延迟执行
void dispatch_after(dispatch_time_t when,dispatch_queue_t queue,dispatch_block_t block);
用法三
//作用:block中的代码块只被执行一次
static dispatch_once_t onceToken;
dispatch_once(&onceToken,^{
//需要执行的代码块
});
用法三
//作用:文件剪切,快速迭代
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
NSString *from = @"/Users/Anthony/Desktop/From";
NSString *to = @"/Users/Anthony/Desktop/To";
NSFileManager *mgr = [NSFileManager defaultManager];
NSArray *subPaths = [mgr subpathsAtPath:from];
dispatch_apply(subPaths.count, queue, ^(size_t index) {
NSString *subPath = subPaths[index];
NSString *fromFullPath = [from stringByAppendingPathComponent:subPath];
NSString *toFullPath = [to stringByAppendingPathComponent:subPath];
[mgr moveItemAtPath:fromFullPath toPath:toFullPath error:nil];
NSLog(@"%@--%@",[NSThread currentThread],subPath);
});
用法四
//队列组
dispatch_queue_t queue =dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);�dispatch_group_t group = dispatch_group_create();
//下载图片
dispatch_group_async(dispatch_group_t group,dispath_queue_t queue,^{});
//(保证执行完组里面的所有任务之后,再执行notify函数里面的block)
dispatch_group_notify(dispatch_group_t group,
dispatch_queue_t queue,
dispatch_block_t block);