GCD详解

简介:并发

GCD(全称Grand CentralDispatch) 
纯C语言

GCD优点:app

1.为多核运算提供
2.自动管理线程的生命周期(建立线程、调度任务、销毁线程、),相比NSTread须要手动管理线程和生命周期更方便
3.只须要告诉GCD想要执行什么任务,不须要编写任何线程管理代码

GCD中有两个核心概念: 任务和队列异步

1.任务: 执行什么操做
2.队列: 用来存听任务 (串行队列、并发队列)
3.将任务添加到队列,GCD会自动将队列中任务取出,放到对应线程中执行,任务取出遵循:先进先出,后进后出

 

提早说一下参数类型:async

第一个参数: 队列的名称
第二个参数: 告诉系统须要建立一个并发队列仍是串行队列
DISPATCH_QUEUE_SERIAL :串行
DISPATCH_QUEUE_CONCURRENT 并发
第一个参数: iOS8之前是优先级, iOS8之后是服务质量
iOS8之前
*  - DISPATCH_QUEUE_PRIORITY_HIGH          高优先级 2
*  - DISPATCH_QUEUE_PRIORITY_DEFAULT:      默认的优先级 0
*  - DISPATCH_QUEUE_PRIORITY_LOW:          低优先级 -2
*  - DISPATCH_QUEUE_PRIORITY_BACKGROUND:

iOS8之后
*  - QOS_CLASS_USER_INTERACTIVE  0x21 用户交互(用户迫切想执行任务)
*  - QOS_CLASS_USER_INITIATED    0x19 用户须要
*  - QOS_CLASS_DEFAULT           0x15 默认
*  - QOS_CLASS_UTILITY           0x11 工具(低优先级, 苹果推荐将耗时操做放到这种类型的队列中)
*  - QOS_CLASS_BACKGROUND        0x09 后台
*  - QOS_CLASS_UNSPECIFIED       0x00 没有设置

第二个参数: 废物

  

执行任务: 同步、异步、栅栏函数

同步 dispatch_sync : 只能在当前线程中执行任务,不具有开启新线程的能力工具

dispatch_sync(<#dispatch_queue_t queue#>, <#^(void)block#>)

异步 dispatch_async:能够在新的线程中执行任务,具有开启新线程的能力spa

dispatch_async(<#dispatch_queue_t queue#>, <#^(void)block#>)

另一个执行任务的方法:dispatch_barrier_async 栅栏线程

dispatch_barrier_async(<#dispatch_queue_t queue#>, <#^(void)block#>)

(场景:在前面的任务执行结束后它才执行,并且它后面的任务等它执行完成以后才会执行 注意:这个queue不能是全局的并发队列)code

 

队列:串行与并行orm

使用dispatch_queue_create函数建立队列

dispatch_queue_t dispatch_queue_create(
    const char *Label,//队列名称
    dispatch_queue_attr_t attr//队列的类型
);

 

并发队列: 多任务同时执行,开启多个线程

1.手动建立并发队列dispatch_queue_create

dispatch_queue_t queue = dispatch_queue_create(@"队列名称", DISPATCH_QUEUE_CONCURRENT);

2.GCD默认提供全局并发队列dispatch_get_global_queue

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

串行队列:任务一个个的执行

1.手动建立串行队列dispatch_queue_create

dispatch_queue_t queue = dispatch_queue_create(@"队列名称", NULL);

2.系统自带一种特殊串行队列

dispatch_queue_t queue = dispatch_get_main_queue();

 

同步、异步区别

同步: 在当前线程中执行任务,不开辟新的线程
异步:能够在新的线程中执行任务,能够开辟新线程

并发、串行区别

并发: 容许多个任务并发执行
串行: 一个任务执行完以后再执行下一个任务

同步函数 + 主队列(在子队列中进行)

dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
dispatch_async(queue, ^{
    //block会在子线程中执行
    dispatch_queue_t queue = dispatch_get_main_queue();
    dispatch_sync(queue, ^{
        //block必定会在主线程执行
    });
});

异步 + 主队列: 不会建立新的线程,而且任务都是在主线程中执行

dispatch_queue_t queue = dispatch_get_main_queue();
   dispatch_async(queue, ^{
    //只要任务添加到主队列中,那么任务就必定会在主线程中执行
});

同步 + 并发 : 不会建立新的线程

//建立一个并发队列
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
//将任务添加到队列中
dispatch_sync(queue, ^{
    NSLog(@"任务1");
});
dispatch_sync(queue, ^{
    NSLog(@"任务2");
});
dispatch_sync(queue, ^{
    NSLog(@"任务3");
});
NSLog(@"任务");
输出: 任务1 任务2 任务3 任务

 同步 + 串行 : 不会建立新的线程(若是调用同步函数,会等同步函数中得任务执行完以后再执行后面的的代码)

//建立一个串行队列
dispatch_queue_t queue = dispatch_queue_create("aaa", NULL);
//将任务添加到队列中
dispatch_sync(queue, ^{
    NSLog(@"任务1");
});
dispatch_sync(queue, ^{
    NSLog(@"任务2");
});
dispatch_sync(queue, ^{
    NSLog(@"任务3");
});
NSLog(@"任务");

异步 + 串行 : 会开启新的线程(只有一个) 若是调用一步函数,那么不用等函数中得任务执行完毕就能够执行后面的代码

//建立串行队列
dispatch_queue_t queue = dispatch_queue_create("aa", DISPATCH_QUEUE_SERIAL);
dispatch_async(queue, ^{
    NSLog(@"任务1");
});
dispatch_async(queue, ^{
    NSLog(@"任务2");
});
dispatch_async(queue, ^{
    NSLog(@"任务3");
});
NSLog(@"任务");

异步 + 并发 : 会开启新的线程(若是任务多了会开启多个线程)

dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
dispatch_async(queue, ^{
    NSLog(@"任务1");
});
dispatch_async(queue, ^{
    NSLog(@"任务2");
});
dispatch_async(queue, ^{
    NSLog(@"任务3");
});
NSLog(@"任务");

 

线程间的通讯

子线程回到主线程

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    //执行耗时的异步操做
    NSLog(@"1");
});
dispatch_async(dispatch_get_main_queue(), ^{
   //这里使用的是dispatch_async:不用等block执行完,就会调用下面的打印代码,若是替换为使用dispatch_sync同步函数:那么会等block执行更新UI完毕,才会执行最后一句打印代码
    NSLog(@"2");
});
NSLog(@"刷新UI界面结束");

实例:  子线程下载图片,主线程刷新UI

//除主队列之外,随便写一个队列
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
//调用异步函数
dispatch_async(queue, ^{
    //耗费时间
    UIImage * image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://images.cnblogs.com/cnblogs_com/tupx/465992/o_torus_trianglestrip1.JPG"]]];
    dispatch_sync(dispatch_get_main_queue(), ^{
        //刷新主界面
        self.imageView.image = image;
    });
});

 

延时执行

 iOS经常使用延时执行,调用NSObject方法 (performSelector一旦执行号延时任务,不会卡住当前线程)

[self performSelector:@selector(run) withObject:nil afterDelay:1.0];

使用GCD函数

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)), dispatch_get_global_queue(0, 0), ^{
        NSLog(@"3秒后执行");
    });

NSTimer

[NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(startTest) userInfo:nil repeats:NO];
- (void)startTest{
     NSLog(@"---- begin-----");
}

[NSThread sleepForTimeInterval:3]; 延时执行不要使用sleepForTimeInterval (会卡住线程)

[NSThread sleepForTimeInterval:3];卡住线程3秒

 

一次性代码

dispatch_once能够保证函数内代码在程序运行期间值执行一次(不能当作懒加载使用)

static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
    NSLog(@"一次性的代码");
});

 

快速迭代

第一个参数: 须要遍历几回
第二个参数: 决定第三个参数的block在哪一个线程中执行
第三个参数: 回掉
dispatch_apply(10, 队列queue, ^(size_tindex){
  //执行10次代码,index顺序不肯定
});
//定义变量记录原始文件夹和目标文件夹的路径
NSString * sourcePatch = @"/原始文件";
NSString * destPath = @"/目标文件";

//取出原始文件中全部的文件
NSFileManager * manager = [NSFileManager defaultManager];
NSArray * files = [manager subpathsAtPath:sourcePatch];

dispatch_apply(files.count, dispatch_get_global_queue(0, 0), ^(size_t index) {
    NSString *fileName = files[index];
    //生成原始文件的路径
    NSString *sourceFilePath = [sourcePatch stringByAppendingPathComponent:fileName];
    //生成目标文件的路径
    NSString *destFilePath = [destPath stringByAppendingPathComponent:fileName];
    //利用NSFileManager拷贝文件
    [manager moveItemAtPath:sourceFilePath toPath:destFilePath error:nil];
});
相关文章
相关标签/搜索